main.cpp 13 KB

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