httpd.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #include "hv.h"
  2. #include "hssl.h"
  3. #include "hmain.h"
  4. #include "iniparser.h"
  5. #include "HttpServer.h"
  6. #include "hasync.h" // import hv::async
  7. #include "router.h"
  8. hv::HttpServer g_http_server;
  9. hv::HttpService g_http_service;
  10. static void print_version();
  11. static void print_help();
  12. static int parse_confile(const char* confile);
  13. // short options
  14. static const char options[] = "hvc:ts:dp:";
  15. // long options
  16. static const option_t long_options[] = {
  17. {'h', "help", NO_ARGUMENT},
  18. {'v', "version", NO_ARGUMENT},
  19. {'c', "confile", REQUIRED_ARGUMENT},
  20. {'t', "test", NO_ARGUMENT},
  21. {'s', "signal", REQUIRED_ARGUMENT},
  22. {'d', "daemon", NO_ARGUMENT},
  23. {'p', "port", REQUIRED_ARGUMENT}
  24. };
  25. static const char detail_options[] = R"(
  26. -h|--help Print this information
  27. -v|--version Print version
  28. -c|--confile <confile> Set configure file, default etc/{program}.conf
  29. -t|--test Test configure file and exit
  30. -s|--signal <signal> Send <signal> to process,
  31. <signal>=[start,stop,restart,status,reload]
  32. -d|--daemon Daemonize
  33. -p|--port <port> Set listen port
  34. )";
  35. void print_version() {
  36. printf("%s version %s\n", g_main_ctx.program_name, hv_compile_version());
  37. }
  38. void print_help() {
  39. printf("Usage: %s [%s]\n", g_main_ctx.program_name, options);
  40. printf("Options:\n%s\n", detail_options);
  41. }
  42. int parse_confile(const char* confile) {
  43. IniParser ini;
  44. int ret = ini.LoadFromFile(confile);
  45. if (ret != 0) {
  46. printf("Load confile [%s] failed: %d\n", confile, ret);
  47. exit(-40);
  48. }
  49. // logfile
  50. std::string str = ini.GetValue("logfile");
  51. if (!str.empty()) {
  52. strncpy(g_main_ctx.logfile, str.c_str(), sizeof(g_main_ctx.logfile));
  53. }
  54. hlog_set_file(g_main_ctx.logfile);
  55. // loglevel
  56. str = ini.GetValue("loglevel");
  57. if (!str.empty()) {
  58. hlog_set_level_by_str(str.c_str());
  59. }
  60. // log_filesize
  61. str = ini.GetValue("log_filesize");
  62. if (!str.empty()) {
  63. hlog_set_max_filesize_by_str(str.c_str());
  64. }
  65. // log_remain_days
  66. str = ini.GetValue("log_remain_days");
  67. if (!str.empty()) {
  68. hlog_set_remain_days(atoi(str.c_str()));
  69. }
  70. // log_fsync
  71. str = ini.GetValue("log_fsync");
  72. if (!str.empty()) {
  73. logger_enable_fsync(hlog, hv_getboolean(str.c_str()));
  74. }
  75. hlogi("%s version: %s", g_main_ctx.program_name, hv_compile_version());
  76. hlog_fsync();
  77. // worker_processes
  78. int worker_processes = 0;
  79. #ifdef DEBUG
  80. // Disable multi-processes mode for debugging
  81. worker_processes = 0;
  82. #else
  83. str = ini.GetValue("worker_processes");
  84. if (str.size() != 0) {
  85. if (strcmp(str.c_str(), "auto") == 0) {
  86. worker_processes = get_ncpu();
  87. hlogd("worker_processes=ncpu=%d", worker_processes);
  88. }
  89. else {
  90. worker_processes = atoi(str.c_str());
  91. }
  92. }
  93. #endif
  94. g_http_server.worker_processes = LIMIT(0, worker_processes, MAXNUM_WORKER_PROCESSES);
  95. // worker_threads
  96. int worker_threads = 0;
  97. str = ini.GetValue("worker_threads");
  98. if (str.size() != 0) {
  99. if (strcmp(str.c_str(), "auto") == 0) {
  100. worker_threads = get_ncpu();
  101. hlogd("worker_threads=ncpu=%d", worker_threads);
  102. }
  103. else {
  104. worker_threads = atoi(str.c_str());
  105. }
  106. }
  107. g_http_server.worker_threads = LIMIT(0, worker_threads, 64);
  108. // http_port
  109. int port = 0;
  110. const char* szPort = get_arg("p");
  111. if (szPort) {
  112. port = atoi(szPort);
  113. }
  114. if (port == 0) {
  115. port = ini.Get<int>("port");
  116. }
  117. if (port == 0) {
  118. port = ini.Get<int>("http_port");
  119. }
  120. g_http_server.port = port;
  121. // https_port
  122. if (HV_WITH_SSL) {
  123. g_http_server.https_port = ini.Get<int>("https_port");
  124. }
  125. if (g_http_server.port == 0 && g_http_server.https_port == 0) {
  126. printf("Please config listen port!\n");
  127. exit(-10);
  128. }
  129. // base_url
  130. str = ini.GetValue("base_url");
  131. if (str.size() != 0) {
  132. g_http_service.base_url = str;
  133. }
  134. // document_root
  135. str = ini.GetValue("document_root");
  136. if (str.size() != 0) {
  137. g_http_service.document_root = str;
  138. }
  139. // home_page
  140. str = ini.GetValue("home_page");
  141. if (str.size() != 0) {
  142. g_http_service.home_page = str;
  143. }
  144. // error_page
  145. str = ini.GetValue("error_page");
  146. if (str.size() != 0) {
  147. g_http_service.error_page = str;
  148. }
  149. // index_of
  150. str = ini.GetValue("index_of");
  151. if (str.size() != 0) {
  152. g_http_service.index_of = str;
  153. }
  154. // limit_rate
  155. str = ini.GetValue("limit_rate");
  156. if (str.size() != 0) {
  157. g_http_service.limit_rate = atoi(str.c_str());
  158. }
  159. // ssl
  160. if (g_http_server.https_port > 0) {
  161. std::string crt_file = ini.GetValue("ssl_certificate");
  162. std::string key_file = ini.GetValue("ssl_privatekey");
  163. std::string ca_file = ini.GetValue("ssl_ca_certificate");
  164. hlogi("SSL backend is %s", hssl_backend());
  165. hssl_ctx_init_param_t param;
  166. memset(&param, 0, sizeof(param));
  167. param.crt_file = crt_file.c_str();
  168. param.key_file = key_file.c_str();
  169. param.ca_file = ca_file.c_str();
  170. param.endpoint = HSSL_SERVER;
  171. if (hssl_ctx_init(&param) == NULL) {
  172. hloge("SSL certificate verify failed!");
  173. exit(0);
  174. }
  175. else {
  176. hlogi("SSL certificate verify ok!");
  177. }
  178. }
  179. hlogi("parse_confile('%s') OK", confile);
  180. return 0;
  181. }
  182. static void on_reload(void* userdata) {
  183. hlogi("reload confile [%s]", g_main_ctx.confile);
  184. parse_confile(g_main_ctx.confile);
  185. }
  186. int main(int argc, char** argv) {
  187. // g_main_ctx
  188. main_ctx_init(argc, argv);
  189. //int ret = parse_opt(argc, argv, options);
  190. int ret = parse_opt_long(argc, argv, long_options, ARRAY_SIZE(long_options));
  191. if (ret != 0) {
  192. print_help();
  193. exit(ret);
  194. }
  195. // help
  196. if (get_arg("h")) {
  197. print_help();
  198. exit(0);
  199. }
  200. // version
  201. if (get_arg("v")) {
  202. print_version();
  203. exit(0);
  204. }
  205. // parse_confile
  206. const char* confile = get_arg("c");
  207. if (confile) {
  208. strncpy(g_main_ctx.confile, confile, sizeof(g_main_ctx.confile));
  209. }
  210. parse_confile(g_main_ctx.confile);
  211. // test
  212. if (get_arg("t")) {
  213. printf("Test confile [%s] OK!\n", g_main_ctx.confile);
  214. exit(0);
  215. }
  216. // signal
  217. signal_init(on_reload);
  218. const char* signal = get_arg("s");
  219. if (signal) {
  220. signal_handle(signal);
  221. }
  222. #ifdef OS_UNIX
  223. // daemon
  224. if (get_arg("d")) {
  225. // nochdir, noclose
  226. int ret = daemon(1, 1);
  227. if (ret != 0) {
  228. printf("daemon error: %d\n", ret);
  229. exit(-10);
  230. }
  231. }
  232. #endif
  233. // pidfile
  234. create_pidfile();
  235. // http_server
  236. Router::Register(g_http_service);
  237. g_http_server.registerHttpService(&g_http_service);
  238. #if 0
  239. std::atomic_flag init_flag = ATOMIC_FLAG_INIT;
  240. g_http_server.onWorkerStart = [&init_flag](){
  241. if (!init_flag.test_and_set()) {
  242. hv::async::startup();
  243. }
  244. };
  245. g_http_server.onWorkerStop = [&init_flag](){
  246. if (init_flag.test_and_set()) {
  247. hv::async::cleanup();
  248. }
  249. };
  250. #endif
  251. g_http_server.run();
  252. return ret;
  253. }