]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Handle ctrl-C and ctrl-break events on Windows
authorSelva Nair <selva.nair@gmail.com>
Tue, 17 Nov 2015 02:48:09 +0000 (21:48 -0500)
committerGert Doering <gert@greenie.muc.de>
Sun, 22 Nov 2015 16:09:59 +0000 (17:09 +0100)
v2 changes
 - cleaner, hopefully easier to get a code review :)
 - handles both console mode and service mode
-- >8 --

Handle ctrl-C or ctrl-Break sent to the console as a SIGTERM.
Depending on the console mode, windows delivers ctrl-C as a
keyboard input or as a signal. We handle both cases. This allows
graceful termination of openvpn from programs such as nssm.
Works in both console mode and service mode.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1447728489-14991-1-git-send-email-selva.nair@gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10513
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/win32.c

index d06b41f1641b9e61a84a00e127d13936c081c097..1f9bda05624a4b3e6d1c2bcf80df57de7a787dc6 100644 (file)
@@ -324,6 +324,53 @@ net_event_win32_close (struct net_event_win32 *ne)
  * (2) Service mode -- map Windows event object to SIGTERM
  */
 
+static void
+win_trigger_event(struct win32_signal *ws)
+{
+  if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read))
+    SetEvent (ws->in.read);
+  else /* generate a key-press event */
+    {
+      DWORD tmp;
+      INPUT_RECORD ir;
+      HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+      CLEAR(ir);
+      ir.EventType = KEY_EVENT;
+      ir.Event.KeyEvent.bKeyDown = true;
+      if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp))
+        msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput");
+    }
+}
+
+/*
+ * Callback to handle console ctrl events
+ */
+static bool WINAPI
+win_ctrl_handler (DWORD signum)
+{
+  msg(D_LOW, "win_ctrl_handler: signal received (code=%lu)", (unsigned long) signum);
+
+  if (siginfo_static.signal_received == SIGTERM)
+     return true;
+
+  switch (signum)
+    {
+    case CTRL_C_EVENT:
+    case CTRL_BREAK_EVENT:
+      throw_signal(SIGTERM);
+      /* trigget the win32_signal to interrupt the event loop */
+      win_trigger_event(&win32_signal);
+      return true;
+      break;
+    default:
+      msg(D_LOW, "win_ctrl_handler: signal (code=%lu) not handled", (unsigned long) signum);
+      break;
+    }
+  /* pass all other signals to the next handler */
+  return false;
+}
+
 void
 win32_signal_clear (struct win32_signal *ws)
 {
@@ -403,6 +450,9 @@ win32_signal_open (struct win32_signal *ws,
            ws->mode = WSO_MODE_SERVICE;
        }
     }
+    /* set the ctrl handler in both console and service modes */
+    if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE) win_ctrl_handler, true))
+       msg (M_WARN|M_ERRNO, "WARN: SetConsoleCtrlHandler failed");
 }
 
 static bool
@@ -512,6 +562,9 @@ win32_signal_get (struct win32_signal *ws)
            case 0x3E: /* F4 -> TERM */
              ret = SIGTERM;
              break;
+           case 0x03: /* CTRL-C -> TERM */
+             ret = SIGTERM;
+             break;
            }
        }
       if (ret)