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 the openvpn from programs such as nssm.

Signed-off-by: Selva Nair <selva.n...@gmail.com>
---
 src/openvpn/win32.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index 7c89a5a..feae73c 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -324,6 +324,55 @@ net_event_win32_close (struct net_event_win32 *ne)
  * (2) Service mode -- map Windows event object to SIGTERM
  */

+static bool
+win_keyboard_put_ctrlC (HANDLE stdin_handle)
+{
+  DWORD tmp;
+  INPUT_RECORD ir;
+
+  CLEAR(ir);
+  ir.EventType = KEY_EVENT;
+  ir.Event.KeyEvent.bKeyDown = true;
+  ir.Event.KeyEvent.wRepeatCount = 1;
+  ir.Event.KeyEvent.uChar.AsciiChar = 0x03; /* ctrl-C */
+  if (WriteConsoleInput(stdin_handle, &ir, 1, &tmp))
+     return true;
+  else
+     return false;
+}
+
+/*
+ * Callback to handle console ctrl events
+ */
+static bool
+win_ctrl_handler (DWORD signum)
+{
+  msg(D_LOW, "win_ctrl_handler: signal received (code=%d)", signum);
+
+  HANDLE stdin_handle = GetStdHandle (STD_INPUT_HANDLE);
+  if (stdin_handle == INVALID_HANDLE_VALUE)
+  {
+     msg(M_WARN, "Warning: win_ctrl_handler: no console input, signal not 
handled");
+     return false;
+  }
+
+  switch (signum)
+    {
+    case CTRL_C_EVENT:
+    case CTRL_BREAK_EVENT:
+      if (win_keyboard_put_ctrlC (stdin_handle))
+        return true;
+      else
+        msg(M_NONFATAL, "win_ctrl_handler: write to console input failed");
+      break;
+    default:
+      msg(D_LOW, "win_ctrl_handler: unknown signal (code=%d) not handled", 
signum);
+      break;
+    }
+  /* pass all other signals to the next handler */
+  return false;
+}
+
 void
 win32_signal_clear (struct win32_signal *ws)
 {
@@ -369,6 +418,8 @@ win32_signal_open (struct win32_signal *ws,
                  ws->console_mode_save_defined = true;
                }
              ws->mode = WSO_MODE_CONSOLE;
+             if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE) win_ctrl_handler, 
true))
+                msg (M_NONFATAL, "Error: win32_signal_open: 
SetConsoleCtrlHandler failed");
            }
          else
            ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a 
service */
@@ -512,6 +563,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)
-- 
2.6.2


Reply via email to