main.cpp 13 KB

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