main.cpp 13 KB

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