main.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #include "main.h"
  2. #include "projal.h"
  3. #include "helpers.h"
  4. #include "callback.h"
  5. #include "instance.h"
  6. #if _REST_USE_SSL
  7. #include "keys.c"
  8. #endif // _REST_USE_SSL
  9. #if _REST_LINEAR_GET
  10. #define GetShmPostResponseCallback GetShmPostResponseCallback_M
  11. #else // _REST_LINEAR_GET
  12. #define GetShmPostResponseCallback GetShmPostResponseCallback_O
  13. #endif // _REST_LINEAR_GET
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////
  15. // app control
  16. #define _APPID GFA_APPCTRL_APPID_REST
  17. #define _APPNAME "REST"
  18. #define _DEPENDENCIES ((appid_t)(GFA_APPCTRL_APPID_REMANENT))
  19. #define _REST_CYCLE_INTV_MS 200
  20. /////////////////////////////////////////////////////////////////////////////
  21. static volatile bool g_fRun = false;
  22. static volatile bool g_fPauseImp = false;
  23. static volatile bool g_fPauseCmd = false;
  24. static volatile bool g_fZombie = false;
  25. static appid_t g_nDepRunning = 0;
  26. static sigset_t g_set;
  27. int g_nLastSig = -1;
  28. /////////////////////////////////////////////////////////////////////////////
  29. static void _SigHandler(int sig)
  30. {
  31. g_nLastSig = sig;
  32. g_fRun = g_fPauseImp = g_fPauseCmd = g_fZombie = false;
  33. }
  34. /////////////////////////////////////////////////////////////////////////////
  35. static void _ProcessCtrlMessages(HAPPCTRL hAC, HAPPINFO hAI)
  36. {
  37. ctrlmsg_t nCtrlMsg;
  38. while(g_fRun && (nCtrlMsg = ::GfaIpcAppCtrlGetNextCtrlMsg(hAI)))
  39. {
  40. switch(nCtrlMsg)
  41. {
  42. case GFA_APPCTRL_CTRLMSG_STOP:
  43. g_fRun = false;
  44. g_fPauseImp = false;
  45. g_fPauseCmd = false;
  46. g_fZombie = false;
  47. TRACE("Received Control Message 'Stop'\n");
  48. return;
  49. case GFA_APPCTRL_CTRLMSG_PAUSE:
  50. if(!g_fPauseCmd)
  51. {
  52. g_fPauseCmd = true;
  53. if(!g_fPauseImp)
  54. {
  55. ::GfaIpcAppCtrlSetState(hAC, GIAS_Paused);
  56. TRACE("Received Control Message 'Pause'\n");
  57. TRACE("%-8s: State: %s\n", "Me", ::GfaIpcAppCtrlGetStateText(GIAS_Paused));
  58. }
  59. }
  60. break;
  61. case GFA_APPCTRL_CTRLMSG_RESUME:
  62. if(g_fPauseCmd)
  63. {
  64. g_fPauseCmd = false;
  65. if(!g_fPauseImp)
  66. {
  67. TRACE("Received Control Message 'Resume'\n");
  68. ::GfaIpcAppCtrlSetState(hAC, GIAS_Running);
  69. TRACE("%-8s: State: %s\n", "Me", ::GfaIpcAppCtrlGetStateText(GIAS_Running));
  70. }
  71. }
  72. break;
  73. default:
  74. break;
  75. }
  76. }
  77. }
  78. /////////////////////////////////////////////////////////////////////////////
  79. static void _ProcessStateEvents(HAPPCTRL hAC, HAPPINFO hAI)
  80. {
  81. appid_t nAppIdSrc;
  82. bool fOldPaused = g_fPauseImp;
  83. char szDispName[128];
  84. while(g_fRun && (nAppIdSrc = ::GfaIpcAppCtrlGetNextStateEvtSrc(hAI)))
  85. {
  86. GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(hAC, nAppIdSrc);
  87. GfaIpcAppCtrlGetDisplayName(hAC, nAppIdSrc, szDispName, sizeof(szDispName));
  88. TRACE("%-8s: State: %s\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
  89. if(nAppIdSrc & _DEPENDENCIES)
  90. {
  91. if(state == GIAS_Running)
  92. {
  93. TRACE("%s -> %s.\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
  94. g_nDepRunning |= nAppIdSrc;
  95. }
  96. else
  97. {
  98. TRACE("%s -> %s.\n", szDispName, ::GfaIpcAppCtrlGetStateText(state));
  99. g_nDepRunning &= ~nAppIdSrc;
  100. }
  101. }
  102. }
  103. if(g_fRun)
  104. {
  105. g_fPauseImp = (g_nDepRunning != _DEPENDENCIES);
  106. if(!g_fPauseCmd && (fOldPaused != g_fPauseImp))
  107. {
  108. fOldPaused = g_fPauseImp;
  109. GfaIpcAppStates newState = g_fPauseImp ? GIAS_Paused : GIAS_Running;
  110. ::GfaIpcAppCtrlSetState(hAC, newState);
  111. if(g_fPauseImp)
  112. {
  113. TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(newState));
  114. }
  115. else
  116. {
  117. TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(newState));
  118. }
  119. }
  120. }
  121. }
  122. /////////////////////////////////////////////////////////////////////////////
  123. // main
  124. int main(int argc, char *argv[])
  125. {
  126. UNUSED(argc);
  127. UNUSED(argv);
  128. int nRet = 0;
  129. HSHM hShm = NULL;
  130. void *pShm = NULL;
  131. HAPPCTRL hAC = NULL;
  132. HAPPINFO hAI;
  133. struct _u_instance instance;
  134. CURLcode cuGlobInit = CURL_LAST;
  135. int ulfInit = U_ERROR, ulfStart = U_ERROR;
  136. bool bUlfFrmwrkStarted = false;
  137. /////////////////////////////////////////////////////////////////////////
  138. // check for multiple instances
  139. CProcessInstance pi;
  140. if(!pi.LockInstance(UUID_SHM))
  141. {
  142. ETRACE("Failed to start instance!\n");
  143. return -1;
  144. }
  145. /////////////////////////////////////////////////////////////////////////
  146. do
  147. {
  148. char szRootDir[PATH_MAX];
  149. const char *pszRootDir;
  150. json_error_t jerr;
  151. g_fZombie = true;
  152. /////////////////////////////////////////////////////////////
  153. // configure signal handling
  154. struct sigaction sa;
  155. memset(&sa, 0, sizeof(sa));
  156. sigfillset(&g_set);
  157. // handle signals
  158. sa.sa_handler = _SigHandler;
  159. sigaction(SIGHUP, &sa, NULL); // handles user's terminal disconnect
  160. sigaction(SIGQUIT, &sa, NULL); // handles Ctrl + '\'
  161. sigaction(SIGTERM, &sa, NULL); // handles normal termination
  162. sigaction(SIGABRT, &sa, NULL); // handles abnormal termination (i.e. abort())
  163. sigaction(SIGINT, &sa, NULL); // handles Ctrl + 'C'
  164. // ignore signals
  165. sa.sa_handler = SIG_IGN;
  166. sigaction(SIGTSTP, &sa, NULL); // ignores Ctrl + 'Z'
  167. sigaction(SIGSTOP, &sa, NULL); // ignores Stop
  168. sigaction(SIGCONT, &sa, NULL); // ignores Continue
  169. sigaction(SIGCHLD, &sa, NULL); // ignores child process termination
  170. sigaction(0, &sa, NULL); // ignores shell termination
  171. /////////////////////////////////////////////////////////////
  172. // initialize app control
  173. if(!(hAC = ::GfaIpcAppCtrlAcquire(_APPID, _APPNAME, _REST_CYCLE_INTV_MS * 1000, _REST_CYCLE_INTV_MS * 3000)))
  174. {
  175. ETRACE("Failed to acquire AppCtrl-Handle!\n");
  176. nRet = -1;
  177. break;
  178. }
  179. ::GfaIpcAppCtrlSetState(hAC, GIAS_Initializing);
  180. TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(GIAS_Initializing));
  181. if(!::GfaIpcAppCtrlSubscribeStateEvents(hAC, _DEPENDENCIES))
  182. {
  183. ETRACE("Failed to subscribe state event notifications!\n");
  184. nRet = -1;
  185. break;
  186. }
  187. /////////////////////////////////////////////////////////////////////
  188. pszRootDir = GetAppDirectory(szRootDir, _COUNTOF(szRootDir));
  189. /////////////////////////////////////////////////////////////////////
  190. // initialize CURL
  191. if((cuGlobInit = curl_global_init(CURL_GLOBAL_ALL)) != CURLE_OK)
  192. {
  193. ETRACE("Failed to initialize CURL!\n");
  194. nRet = -1;
  195. break;
  196. }
  197. if(!(hShm = acquire_shm(sizeof(shm_t))))
  198. {
  199. ETRACE("GfaIpcAcquireSHM failed!\n");
  200. nRet = -1;
  201. break;
  202. }
  203. if(!(pShm = GfaIpcAcquirePointer(hShm)))
  204. {
  205. ETRACE("GfaIpcAcquirePointer failed!\n");
  206. nRet = -1;
  207. break;
  208. }
  209. #ifdef _DEBUG
  210. GfaIpcDumpSHMROT();
  211. fflush(stdout);
  212. #endif // _DEBUG
  213. /////////////////////////////////////////////////////////////////////
  214. if((ulfInit = ulfius_init_instance(&instance, _REST_PORT, NULL, NULL)) != U_OK)
  215. {
  216. ETRACE("ulfius_init_instance failed!\n");
  217. nRet = -1;
  218. break;
  219. }
  220. /////////////////////////////////////////////////////////////////////
  221. // SHM and SHM variables table
  222. CRestVarTable map;
  223. CShm_t shm(pShm, hShm);
  224. shm.InitPath(NULL, NULL);
  225. shm.CreateMembersTable(map);
  226. /////////////////////////////////////////////////////////////////////
  227. // initialize request parameters
  228. SHM_REQUEST_PARAMS srp;
  229. srp.pMap = ↦
  230. srp.pszUuid = UUID_SHM;
  231. /////////////////////////////////////////////////////////////////////
  232. /////////////////////////////////////////////////////////////////////
  233. // add handler functions
  234. // initialize static files if any
  235. if(InitializeStaticFiles(pszRootDir, &instance, jerr) < 0)
  236. {
  237. ETRACE("InitializeStaticFiles failed!\n");
  238. nRet = -1;
  239. break;
  240. }
  241. /////////////////////////////////////////////////////////////////////
  242. // POST
  243. if(ulfius_add_endpoint_by_val(&instance, "POST", GET_SHM_PREFIX, NULL, 0, &GetShmPostResponseCallback, &srp) != U_OK)
  244. {
  245. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  246. nRet = -1;
  247. break;
  248. }
  249. if(ulfius_add_endpoint_by_val(&instance, "POST", SET_SHM_PREFIX, NULL, 0, &SetShmPostResponseCallback, &srp) != U_OK)
  250. {
  251. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  252. nRet = -1;
  253. break;
  254. }
  255. #if _REST_IMPLEMENT_GET
  256. /////////////////////////////////////////////////////////////////////
  257. // GET
  258. if(ulfius_add_endpoint_by_val(&instance, "GET", GET_SHM_PREFIX, "/*", 0, &GetShmGetResponseCallback, &srp) != U_OK)
  259. {
  260. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  261. nRet = -1;
  262. break;
  263. }
  264. #endif // _REST_IMPLEMENT_GET
  265. /////////////////////////////////////////////////////////////////////
  266. // OPTIONS
  267. if(ulfius_add_endpoint_by_val(&instance, "OPTIONS", NULL, "/*", 0, &OptionsResponseCallback, NULL) != U_OK)
  268. {
  269. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  270. nRet = -1;
  271. break;
  272. }
  273. /////////////////////////////////////////////////////////////////////
  274. // handler for HTTP verbs that are not allowed
  275. if(ulfius_add_endpoint_by_val(&instance, "HEAD", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  276. {
  277. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  278. nRet = -1;
  279. break;
  280. }
  281. if(ulfius_add_endpoint_by_val(&instance, "PUT", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  282. {
  283. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  284. nRet = -1;
  285. break;
  286. }
  287. if(ulfius_add_endpoint_by_val(&instance, "DELETE", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  288. {
  289. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  290. nRet = -1;
  291. break;
  292. }
  293. if(ulfius_add_endpoint_by_val(&instance, "CONNECT", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  294. {
  295. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  296. nRet = -1;
  297. break;
  298. }
  299. if(ulfius_add_endpoint_by_val(&instance, "TRACE", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  300. {
  301. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  302. nRet = -1;
  303. break;
  304. }
  305. if(ulfius_add_endpoint_by_val(&instance, "PATCH", NULL, "/*", 0, &NotAllowedResponseCallback, NULL) != U_OK)
  306. {
  307. ETRACE("ulfius_add_endpoint_by_val failed!\n");
  308. nRet = -1;
  309. break;
  310. }
  311. /////////////////////////////////////////////////////////////////////
  312. // start service
  313. #if _REST_USE_SSL
  314. if((ulfStart = ulfius_start_secure_framework(&instance, g_pszKeyPem, g_pszCertPem)) != U_OK)
  315. #else // _REST_USE_SSL
  316. if((ulfStart = ulfius_start_framework(&instance)) != U_OK)
  317. #endif // _REST_USE_SSL
  318. {
  319. ETRACE("ulfius_start_framework failed!\n");
  320. nRet = -1;
  321. break;
  322. }
  323. TRACE("Service started at port %hu.\n", instance.port);
  324. bUlfFrmwrkStarted = true;
  325. g_fZombie = false;
  326. g_fRun = true;
  327. ::GfaIpcAppCtrlSetState(hAC, GIAS_Running);
  328. }
  329. while(false);
  330. /////////////////////////////////////////////////////////////////////////
  331. /////////////////////////////////////////////////////////////////////////
  332. /////////////////////////////////////////////////////////////////////////
  333. while(g_fRun)
  334. {
  335. ////////////////////////////////////////////////////////////////////////////////////////
  336. // update app control info
  337. if((hAI = ::GfaIpcAppCtrlInfoUpdate(hAC, 0)))
  338. {
  339. _ProcessCtrlMessages(hAC, hAI);
  340. if(!g_fRun)
  341. break;
  342. _ProcessStateEvents(hAC, hAI);
  343. }
  344. if(bUlfFrmwrkStarted && (g_fPauseImp || g_fPauseCmd))
  345. {
  346. ulfius_stop_framework(&instance);
  347. bUlfFrmwrkStarted = false;
  348. TRACE("Service exit.\n");
  349. }
  350. else if(!bUlfFrmwrkStarted && !g_fPauseImp && !g_fPauseCmd)
  351. {
  352. #if _REST_USE_SSL
  353. if((ulfStart = ulfius_start_secure_framework(&instance, g_pszKeyPem, g_pszCertPem)) != U_OK)
  354. #else // _REST_USE_SSL
  355. if((ulfStart = ulfius_start_framework(&instance)) != U_OK)
  356. #endif // _REST_USE_SSL
  357. {
  358. ETRACE("ulfius_start_framework failed!\n");
  359. g_fZombie = true;
  360. g_fRun = false;
  361. nRet = -1;
  362. break;
  363. }
  364. bUlfFrmwrkStarted = true;
  365. TRACE("Service started at port %hu.\n", instance.port);
  366. }
  367. usleep(_REST_CYCLE_INTV_MS * 1000);
  368. }
  369. /////////////////////////////////////////////////////////////////////////
  370. /////////////////////////////////////////////////////////////////////////
  371. /////////////////////////////////////////////////////////////////////////
  372. if(g_nLastSig >= 0)
  373. {
  374. TRACE("Received signal '%s'.\n", strsignal(g_nLastSig));
  375. g_nLastSig = -1;
  376. }
  377. if(bUlfFrmwrkStarted)
  378. {
  379. ulfius_stop_framework(&instance);
  380. TRACE("Service exit.\n");
  381. }
  382. if(ulfInit == U_OK)
  383. ulfius_clean_instance(&instance);
  384. if(hShm)
  385. {
  386. if(pShm)
  387. {
  388. TRACE("Releasing SHM Pointer ...\n");
  389. ::GfaIpcReleasePointer(hShm, pShm);
  390. }
  391. TRACE("Releasing SHM Handle ...\n");
  392. ::GfaIpcReleaseSHM(hShm);
  393. }
  394. if(cuGlobInit == CURLE_OK)
  395. curl_global_cleanup();
  396. if(g_fZombie)
  397. {
  398. if(hAC)
  399. ::GfaIpcAppCtrlSetState(hAC, GIAS_Zombie);
  400. TRACE("Enter Zombie state ...\n");
  401. pause();
  402. if(g_nLastSig >= 0)
  403. {
  404. TRACE("Received signal '%s'.\n", strsignal(g_nLastSig));
  405. }
  406. }
  407. if(hAC)
  408. {
  409. // TRACE("Enter state %s ...\n", ::GfaIpcAppCtrlGetStateText(GIAS_Terminating));
  410. ::GfaIpcAppCtrlSetState(hAC, GIAS_Terminating);
  411. TRACE("Releasing App Control ...\n");
  412. ::GfaIpcAppCtrlRelease(hAC);
  413. }
  414. TRACE("Process exit.\n");
  415. return nRet;
  416. }