浏览代码

Windows service functionality, and initial systray functionality

valenok 15 年之前
父节点
当前提交
f169d153c4
共有 1 个文件被更改,包括 161 次插入34 次删除
  1. 161 34
      main.c

+ 161 - 34
main.c

@@ -32,6 +32,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stddef.h>
+#include <stdarg.h>
 
 #include "mongoose.h"
 
@@ -40,26 +41,27 @@
 #include <winsvc.h>
 #define PATH_MAX MAX_PATH
 #define S_ISDIR(x) ((x) & _S_IFDIR)
-#define DIRSEP			'\\'
-#define	snprintf		_snprintf
-#if !defined(__LCC__)
-#define	strdup(x)		_strdup(x)
-#endif /* !MINGW */
-#define	sleep(x)		Sleep((x) * 1000)
+#define DIRSEP '\\'
+#define	snprintf _snprintf
+#define	vsnprintf _vsnprintf
+#define	sleep(x) Sleep((x) * 1000)
 #else
 #include <sys/wait.h>
-#include <unistd.h>		/* For pause() */
+#include <unistd.h>
 #define DIRSEP '/'
-#endif /* _WIN32 */
+#endif // _WIN32
+
+#define MAX_OPTIONS 40
 
-static int exit_flag;	                /* Program termination flag	*/
+static int exit_flag;
+static char *options[MAX_OPTIONS];
+static char server_name[40];
+static struct mg_context *ctx;
 
 #if !defined(CONFIG_FILE)
 #define	CONFIG_FILE "mongoose.conf"
 #endif /* !CONFIG_FILE */
 
-#define MAX_OPTIONS 40
-
 static void signal_handler(int sig_num) {
 #if !defined(_WIN32)
   if (sig_num == SIGCHLD) {
@@ -72,6 +74,23 @@ static void signal_handler(int sig_num) {
   }
 }
 
+static void die(const char *fmt, ...) {
+  va_list ap;
+  char msg[200];
+
+  va_start(ap, fmt);
+  vsnprintf(msg, sizeof(msg), fmt, ap);
+  va_end(ap);
+
+#if defined(_WIN32)
+  MessageBox(NULL, msg, "Error", MB_OK);
+#else
+  fprintf(stderr, "%s\n", msg);
+#endif
+
+  exit(EXIT_FAILURE);
+}
+
 /*
  * Edit the passwords file.
  */
@@ -108,7 +127,6 @@ static void show_usage_and_exit(void) {
   fprintf(stderr, "See  http://code.google.com/p/mongoose/wiki/MongooseManual"
           " for more details.\n");
   fprintf(stderr, "Example:\n  mongoose -s cert.pem -p 80,443s -d no\n");
-
   exit(EXIT_FAILURE);
 }
 
@@ -124,8 +142,7 @@ static void verify_document_root(const char *root) {
   }
 
   if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode)) {
-    fprintf(stderr, "Invalid root directory: \"%s\"\n", root);
-    exit(EXIT_FAILURE);
+    die("Invalid root directory: \"%s\"", root);
   }
 }
 
@@ -154,8 +171,7 @@ static void set_option(char **options, const char *name, const char *value) {
   }
 
   if (i == MAX_OPTIONS - 3) {
-    fprintf(stderr, "%s\n", "Too many options specified");
-    exit(EXIT_FAILURE);
+    die("%s", "Too many options specified");
   }
 }
 
@@ -181,9 +197,7 @@ static void process_command_line_arguments(char *argv[], char **options) {
   }
   /* If config file was set in command line and open failed, exit */
   if (config_file != NULL && (fp = fopen(config_file, "r")) == NULL) {
-    fprintf(stderr, "cannot open config file %s: %s\n",
-            config_file, strerror(errno));
-    exit(EXIT_FAILURE);
+    die("Cannot open config file %s: %s", config_file, strerror(errno));
   }
 
   if (fp != NULL) {
@@ -199,9 +213,7 @@ static void process_command_line_arguments(char *argv[], char **options) {
         continue;
 
       if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
-        fprintf(stderr, "%s: line %d is invalid\n",
-                config_file, (int) line_no);
-        exit(EXIT_FAILURE);
+        die("%s: line %d is invalid", config_file, (int) line_no);
       }
       set_option(options, opt, val);
     }
@@ -209,7 +221,7 @@ static void process_command_line_arguments(char *argv[], char **options) {
     (void) fclose(fp);
   } else {
     for (i = 1; argv[i] != NULL; i += 2) {
-      if (argv[i][0] != '-' || argv[i + 1] == NULL || argv[i + 1][0] == '-') {
+      if (argv[i][0] != '-' || argv[i + 1] == NULL) {
         show_usage_and_exit();
       }
       set_option(options, &argv[i][1], argv[i + 1]);
@@ -217,11 +229,12 @@ static void process_command_line_arguments(char *argv[], char **options) {
   }
 }
 
-int main(int argc, char *argv[]) {
-  struct mg_context	*ctx;
-  char *options[MAX_OPTIONS];
+static void start_mongoose(int argc, char *argv[]) {
   int i;
 
+  snprintf(server_name, sizeof(server_name),
+           "Mongoose %s web server", mg_version());
+
   /* Edit passwords file if -A option is specified */
   if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A') {
     if (argc != 6) {
@@ -237,7 +250,6 @@ int main(int argc, char *argv[]) {
   }
 
   /* Update config based on command line arguments */
-  options[0] = NULL;
   process_command_line_arguments(argv, options);
 
   /* Setup signal handler: quit on Ctrl-C */
@@ -254,19 +266,134 @@ int main(int argc, char *argv[]) {
   }
 
   if (ctx == NULL) {
-    (void) printf("%s\n", "Cannot initialize Mongoose context");
-    exit(EXIT_FAILURE);
+    die("%s", "Failed to start Mongoose. Maybe some options are "
+        "assigned bad values?\nTry to run with '-e error_log.txt' "
+        "and check error_log.txt for more information.");
   }
+}
 
-  printf("Mongoose %s web server started on port(s) %s with web root [%s]\n",
-         mg_version(), mg_get_option(ctx, "listening_ports"),
-         mg_get_option(ctx, "document_root"));
+#ifdef _WIN32
+static SERVICE_STATUS ss;
+static SERVICE_STATUS_HANDLE hStatus;
 
-  fflush(stdout);
+static void WINAPI ControlHandler(DWORD code) {
+  if (code == SERVICE_CONTROL_STOP || code == SERVICE_CONTROL_SHUTDOWN) {
+    ss.dwWin32ExitCode = 0;
+    ss.dwCurrentState = SERVICE_STOPPED;
+  }
+  SetServiceStatus(hStatus, &ss);
+}
+
+static void WINAPI ServiceMain(void) {
+  ss.dwServiceType = SERVICE_WIN32;
+  ss.dwCurrentState = SERVICE_RUNNING;
+  ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+
+  hStatus = RegisterServiceCtrlHandler(server_name, ControlHandler);
+  SetServiceStatus(hStatus, &ss);
+
+  //Sleep(3000);
+  while (ss.dwCurrentState == SERVICE_RUNNING) {
+    Sleep(1000);
+  }
+  mg_stop(ctx);
+
+  ss.dwCurrentState = SERVICE_STOPPED;
+  ss.dwWin32ExitCode = (DWORD) -1;
+  SetServiceStatus(hStatus, &ss);
+}
+
+static void try_to_run_as_nt_service(void) {
+  static SERVICE_TABLE_ENTRY service_table[] = {
+    {server_name, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
+    {NULL, NULL}
+  };
+
+  if (StartServiceCtrlDispatcher(service_table)) {
+    exit(EXIT_SUCCESS);
+  }
+}
+
+#define	ID_TRAYICON	100
+#define	ID_QUIT		101
+static NOTIFYICONDATA	ni;
+
+static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                   LPARAM lParam) {
+  POINT	pt;
+  HMENU	hMenu; 	 
+
+  switch (msg) {
+
+    case WM_COMMAND:
+      switch (LOWORD(wParam)) {
+        case ID_QUIT:
+          exit(EXIT_SUCCESS);
+          break;
+      }
+      break;
+
+    case WM_USER:
+      switch (lParam) {
+        case WM_RBUTTONUP:
+        case WM_LBUTTONUP:
+        case WM_LBUTTONDBLCLK:
+          hMenu = CreatePopupMenu();
+          AppendMenu(hMenu, 0, ID_QUIT, "Exit");
+          GetCursorPos(&pt);
+          TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL);
+          DestroyMenu(hMenu);
+          break;
+      }
+      break;
+  }
+
+  return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
+  WNDCLASS cls;
+  HWND hWnd;
+  MSG msg;
+
+  // Win32 runtime must prepare __argc and __argv for us
+  start_mongoose(__argc, __argv);
+  try_to_run_as_nt_service();
+
+  memset(&cls, 0, sizeof(cls));
+  cls.lpfnWndProc = (WNDPROC) WindowProc; 
+  cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+  cls.lpszClassName = server_name;
+
+  RegisterClass(&cls);
+  hWnd = CreateWindow(cls.lpszClassName, server_name, WS_OVERLAPPEDWINDOW,
+                      0, 0, 0, 0, NULL, NULL, NULL, NULL);
+  ShowWindow(hWnd, SW_HIDE);
+
+  ni.cbSize = sizeof(ni);
+  ni.uID = ID_TRAYICON;
+  ni.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+  ni.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+  ni.hWnd = hWnd;
+  snprintf(ni.szTip, sizeof(ni.szTip), "%s", server_name);
+  ni.uCallbackMessage = WM_USER;
+  Shell_NotifyIcon(NIM_ADD, &ni);
+
+  while (GetMessage(&msg, hWnd, 0, 0)) { 
+    TranslateMessage(&msg); 
+    DispatchMessage(&msg); 
+  }
+}
+#endif /* _WIN32 */
+
+int main(int argc, char *argv[]) {
+  start_mongoose(argc, argv);
+  printf("%s started on port(s) %s with web root [%s]\n",
+         server_name, mg_get_option(ctx, "listening_ports"),
+         mg_get_option(ctx, "document_root"));
   while (exit_flag == 0) {
     sleep(1);
   }
-
   printf("Exiting on signal %d, waiting for all threads to finish...",
          exit_flag);
   fflush(stdout);