server.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /**
  2. server.c -- AppWeb main program
  3. Copyright (c) All Rights Reserved. See copyright notice at the bottom of the file.
  4. usage: appweb [options]
  5. or: appweb [options] [documents] [[ip][:port] ...]
  6. --config configFile # Use given config file instead
  7. --debugger # Disable timeouts to make debugging easier
  8. --home path # Set the home working directory
  9. --log logFile:level # Log to file file at verbosity level
  10. --name uniqueName # Name for this instance
  11. --version # Output version information
  12. -v # Same as --log stderr:2
  13. */
  14. /********************************* Includes ***********************************/
  15. #include "appweb.h"
  16. #include "esp.h"
  17. /********************************** Locals ************************************/
  18. /*
  19. Global application object. Provides the top level roots of all data objects for the Garbage collector.
  20. Appweb uses garbage collection and all memory must have a reference to stop being reclaimed by the GC.
  21. */
  22. typedef struct AppwebApp {
  23. Mpr *mpr;
  24. cchar *documents;
  25. cchar *home;
  26. cchar *configFile;
  27. char *pathVar;
  28. } AppwebApp;
  29. static AppwebApp *app;
  30. /***************************** Forward Declarations ***************************/
  31. static int changeRoot(cchar *jail);
  32. static int checkEnvironment(cchar *program);
  33. static int createEndpoints(int argc, char **argv);
  34. static int findAppwebConf();
  35. static void manageApp(AppwebApp *app, int flags);
  36. static void usageError();
  37. #if ME_UNIX_LIKE
  38. #elif ME_WIN_LIKE
  39. static long msgProc(HWND hwnd, uint msg, uint wp, long lp);
  40. #endif
  41. /*********************************** Code *************************************/
  42. MAIN(appweb, int argc, char **argv, char **envp)
  43. {
  44. Mpr *mpr;
  45. cchar *argp, *jail;
  46. char *logSpec, *traceSpec;
  47. int argind, status, verbose;
  48. jail = 0;
  49. verbose = 0;
  50. logSpec = 0;
  51. traceSpec = 0;
  52. if ((mpr = mprCreate(argc, argv, MPR_USER_EVENTS_THREAD)) == NULL) {
  53. exit(1);
  54. }
  55. mprSetAppName(ME_NAME, ME_TITLE, ME_VERSION);
  56. if (httpCreate(HTTP_CLIENT_SIDE | HTTP_SERVER_SIDE) == 0) {
  57. exit(2);
  58. }
  59. /*
  60. Allocate the top level application object. ManageApp is the GC manager function and is called
  61. by the GC to mark references in the app object.
  62. */
  63. if ((app = mprAllocObj(AppwebApp, manageApp)) == NULL) {
  64. exit(3);
  65. }
  66. mprAddRoot(app);
  67. mprAddStandardSignals();
  68. app->mpr = mpr;
  69. app->configFile = sclone("appweb.conf");
  70. app->home = mprGetCurrentPath();
  71. app->documents = app->home;
  72. argc = mpr->argc;
  73. argv = (char**) mpr->argv;
  74. for (argind = 1; argind < argc; argind++) {
  75. argp = argv[argind];
  76. if (*argp != '-') {
  77. break;
  78. }
  79. if (smatch(argp, "--config") || smatch(argp, "--conf")) {
  80. if (argind >= argc) {
  81. usageError();
  82. }
  83. app->configFile = sclone(argv[++argind]);
  84. #if ME_UNIX_LIKE
  85. } else if (smatch(argp, "--chroot")) {
  86. if (argind >= argc) {
  87. usageError();
  88. }
  89. jail = mprGetAbsPath(argv[++argind]);
  90. #endif
  91. } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) {
  92. mprSetDebugMode(1);
  93. } else if (smatch(argp, "--exe")) {
  94. if (argind >= argc) {
  95. usageError();
  96. }
  97. mpr->argv[0] = mprGetAbsPath(argv[++argind]);
  98. mprSetAppPath(mpr->argv[0]);
  99. mprSetModuleSearchPath(NULL);
  100. } else if (smatch(argp, "--home")) {
  101. if (argind >= argc) {
  102. usageError();
  103. }
  104. app->home = mprGetAbsPath(argv[++argind]);
  105. if (chdir(app->home) < 0) {
  106. mprError("%s: Cannot change directory to %s", mprGetAppName(), app->home);
  107. exit(4);
  108. }
  109. } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
  110. if (argind >= argc) {
  111. usageError();
  112. }
  113. logSpec = argv[++argind];
  114. } else if (smatch(argp, "--name") || smatch(argp, "-n")) {
  115. if (argind >= argc) {
  116. usageError();
  117. }
  118. mprSetAppName(argv[++argind], 0, 0);
  119. } else if (smatch(argp, "--trace") || smatch(argp, "-t")) {
  120. if (argind >= argc) {
  121. usageError();
  122. }
  123. traceSpec = argv[++argind];
  124. } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
  125. if (!logSpec) {
  126. logSpec = sfmt("stderr:2");
  127. }
  128. if (!traceSpec) {
  129. traceSpec = sfmt("stderr:2");
  130. }
  131. } else if (*argp == '-' && isdigit((uchar) argp[1])) {
  132. if (!logSpec) {
  133. logSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
  134. }
  135. if (!traceSpec) {
  136. traceSpec = sfmt("stderr:%d", (int) stoi(&argp[1]));
  137. }
  138. } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
  139. mprPrintf("%s\n", ME_VERSION);
  140. exit(0);
  141. } else if (smatch(argp, "-?") || scontains(argp, "-help")) {
  142. usageError();
  143. exit(5);
  144. } else if (*argp == '-') {
  145. mprLog("error appweb", 0, "Unknown switch \"%s\"", argp);
  146. usageError();
  147. exit(5);
  148. }
  149. }
  150. if (logSpec) {
  151. mprStartLogging(logSpec, MPR_LOG_DETAILED | MPR_LOG_CONFIG | MPR_LOG_CMDLINE);
  152. }
  153. if (traceSpec) {
  154. httpStartTracing(traceSpec);
  155. }
  156. /*
  157. Start the multithreaded portable runtime (MPR)
  158. */
  159. if (mprStart() < 0) {
  160. mprError("Cannot start MPR for %s", mprGetAppName());
  161. mprDestroy();
  162. return MPR_ERR_CANT_INITIALIZE;
  163. }
  164. if (checkEnvironment(argv[0]) < 0) {
  165. exit(6);
  166. }
  167. if (findAppwebConf() < 0) {
  168. exit(7);
  169. }
  170. if (jail && changeRoot(jail) < 0) {
  171. exit(8);
  172. }
  173. /*
  174. Open the sockets to listen on
  175. */
  176. if (createEndpoints(argc - argind, &argv[argind]) < 0) {
  177. return MPR_ERR_CANT_INITIALIZE;
  178. }
  179. if (httpStartEndpoints() < 0) {
  180. mprError("Cannot start HTTP service, exiting.");
  181. exit(9);
  182. }
  183. mprServiceEvents(-1, 0);
  184. status = mprGetExitStatus();
  185. mprLog("info appweb", 1, "Stopping Appweb ...");
  186. mprDestroy();
  187. return status;
  188. }
  189. static void manageApp(AppwebApp *app, int flags)
  190. {
  191. if (flags & MPR_MANAGE_MARK) {
  192. mprMark(app->documents);
  193. mprMark(app->configFile);
  194. mprMark(app->pathVar);
  195. mprMark(app->home);
  196. }
  197. }
  198. /*
  199. Move into a chroot jail
  200. */
  201. static int changeRoot(cchar *jail)
  202. {
  203. #if ME_UNIX_LIKE
  204. if (chdir(app->home) < 0) {
  205. mprError("%s: Cannot change directory to %s", mprGetAppName(), app->home);
  206. return MPR_ERR_CANT_INITIALIZE;
  207. }
  208. if (chroot(jail) < 0) {
  209. if (errno == EPERM) {
  210. mprError("%s: Must be super user to use the --chroot option", mprGetAppName());
  211. } else {
  212. mprError("%s: Cannot change change root directory to %s, errno %d", mprGetAppName(), jail, errno);
  213. }
  214. return MPR_ERR_CANT_INITIALIZE;
  215. }
  216. #endif
  217. return 0;
  218. }
  219. /*
  220. Create the listening endoints
  221. */
  222. static int createEndpoints(int argc, char **argv)
  223. {
  224. cchar *ip;
  225. int argind, port, secure;
  226. ip = 0;
  227. port = -1;
  228. argind = 0;
  229. if (argc > argind) {
  230. mprParseSocketAddress(argv[argind++], &ip, &port, &secure, port);
  231. }
  232. if (maConfigureServer(app->configFile, app->home, app->documents, ip, port) < 0) {
  233. return MPR_ERR_CANT_CREATE;
  234. }
  235. return 0;
  236. }
  237. /*
  238. Find the appweb.conf file
  239. */
  240. static int findAppwebConf()
  241. {
  242. cchar *userPath;
  243. userPath = app->configFile;
  244. if (app->configFile == 0) {
  245. app->configFile = mprJoinPathExt(mprGetAppName(), ".conf");
  246. }
  247. if (!mprPathExists(app->configFile, R_OK)) {
  248. if (!userPath) {
  249. app->configFile = mprJoinPath(app->home, "appweb.conf");
  250. if (!mprPathExists(app->configFile, R_OK)) {
  251. app->configFile = mprJoinPath(mprGetAppDir(), sfmt("%s.conf", mprGetAppName()));
  252. }
  253. }
  254. if (!mprPathExists(app->configFile, R_OK)) {
  255. mprError("Cannot open config file \"%s\"", app->configFile);
  256. return MPR_ERR_CANT_OPEN;
  257. }
  258. }
  259. return 0;
  260. }
  261. static void usageError(Mpr *mpr)
  262. {
  263. cchar *name;
  264. name = mprGetAppName();
  265. mprEprintf("\n%s Usage:\n\n"
  266. " %s [options]\n"
  267. " %s [options] documents ip[:port] ...\n\n"
  268. " Without [documents ip:port], %s will read the appweb.conf configuration file.\n\n"
  269. " Options:\n"
  270. " --config configFile # Use named config file instead appweb.conf\n"
  271. " --chroot directory # Change root directory to run more securely (Unix)\n"
  272. " --debugger # Disable timeouts to make debugging easier\n"
  273. " --exe path # Set path to Appweb executable on Vxworks\n"
  274. " --home directory # Change to directory to run\n"
  275. " --log logFile:level # Log to file file at verbosity level\n"
  276. " --name uniqueName # Unique name for this instance\n"
  277. " --verbose # Same as --log stderr:2\n"
  278. " --version # Output version information\n\n",
  279. mprGetAppTitle(), name, name, name);
  280. exit(10);
  281. }
  282. /*
  283. Security checks. Make sure we are staring with a safe environment
  284. */
  285. static int checkEnvironment(cchar *program)
  286. {
  287. #if ME_UNIX_LIKE
  288. app->pathVar = sjoin("PATH=", getenv("PATH"), ":", mprGetAppDir(), NULL);
  289. putenv(app->pathVar);
  290. #endif
  291. return 0;
  292. }
  293. /*
  294. Copyright (c) Embedthis Software. All Rights Reserved.
  295. This software is distributed under commercial and open source licenses.
  296. You may use the Embedthis Open Source license or you may acquire a
  297. commercial license from Embedthis Software. You agree to be fully bound
  298. by the terms of either license. Consult the LICENSE.md distributed with
  299. this software for full details and other copyrights.
  300. */