NCDModule.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /**
  2. * @file NCDModule.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <stdarg.h>
  23. #include <ncd/NCDModule.h>
  24. #define STATE_INIT 1
  25. #define STATE_UNINIT 2
  26. #define STATE_DEAD 3
  27. #define STATE_DOWN_CLEAN 4
  28. #define STATE_UP 5
  29. #define STATE_DOWN_UNCLEAN 6
  30. #define STATE_DOWN_PCLEAN 7
  31. #define STATE_DOWN_DIE 8
  32. #define STATE_UP_DIE 9
  33. #define STATE_DYING 10
  34. #define STATE_UNDEAD 11
  35. #define PROCESS_STATE_INIT 1
  36. #define PROCESS_STATE_DOWN 2
  37. #define PROCESS_STATE_UP_PENDING 3
  38. #define PROCESS_STATE_UP 4
  39. #define PROCESS_STATE_DOWN_PENDING 5
  40. #define PROCESS_STATE_DOWN_WAITING 6
  41. #define PROCESS_STATE_DOWN_CONTINUE_PENDING 7
  42. #define PROCESS_STATE_TERMINATING 8
  43. #define PROCESS_STATE_TERMINATED_PENDING 9
  44. #define PROCESS_STATE_TERMINATED 10
  45. static void frontend_event (NCDModuleInst *n, int event)
  46. {
  47. n->handler_event(n->user, event);
  48. return;
  49. }
  50. static void init_job_handler (NCDModuleInst *n)
  51. {
  52. DebugObject_Access(&n->d_obj);
  53. ASSERT(n->state == STATE_INIT)
  54. n->state = STATE_DOWN_CLEAN;
  55. n->m->func_new(n);
  56. return;
  57. }
  58. static void uninit_job_handler (NCDModuleInst *n)
  59. {
  60. DebugObject_Access(&n->d_obj);
  61. ASSERT(n->state == STATE_UNINIT)
  62. n->state = STATE_UNDEAD;
  63. frontend_event(n, NCDMODULE_EVENT_DEAD);
  64. return;
  65. }
  66. static void die_job_handler (NCDModuleInst *n)
  67. {
  68. DebugObject_Access(&n->d_obj);
  69. ASSERT(n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE)
  70. n->state = STATE_DYING;
  71. n->m->func_die(n->inst_user);
  72. return;
  73. }
  74. static void clean_job_handler (NCDModuleInst *n)
  75. {
  76. DebugObject_Access(&n->d_obj);
  77. ASSERT(n->state == STATE_DOWN_PCLEAN)
  78. n->state = STATE_DOWN_CLEAN;
  79. if (n->m->func_clean) {
  80. n->m->func_clean(n->inst_user);
  81. return;
  82. }
  83. }
  84. static void process_event_job_handler (NCDModuleProcess *o)
  85. {
  86. DebugObject_Access(&o->d_obj);
  87. switch (o->state) {
  88. case PROCESS_STATE_DOWN_CONTINUE_PENDING: {
  89. o->state = PROCESS_STATE_DOWN;
  90. o->interp_func_event(o->interp_user, NCDMODULEPROCESS_INTERP_EVENT_CONTINUE);
  91. } break;
  92. case PROCESS_STATE_UP_PENDING: {
  93. o->state = PROCESS_STATE_UP;
  94. o->handler_event(o->user, NCDMODULEPROCESS_EVENT_UP);
  95. return;
  96. } break;
  97. case PROCESS_STATE_DOWN_PENDING: {
  98. o->state = PROCESS_STATE_DOWN_WAITING;
  99. o->handler_event(o->user, NCDMODULEPROCESS_EVENT_DOWN);
  100. return;
  101. } break;
  102. case PROCESS_STATE_TERMINATED_PENDING: {
  103. o->state = PROCESS_STATE_TERMINATED;
  104. o->handler_event(o->user, NCDMODULEPROCESS_EVENT_TERMINATED);
  105. return;
  106. } break;
  107. default: ASSERT(0);
  108. }
  109. }
  110. void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, NCDModuleInst *method_object, NCDValue *args, BReactor *reactor, BProcessManager *manager, NCDUdevManager *umanager, void *user,
  111. NCDModule_handler_event handler_event,
  112. NCDModule_handler_getvar handler_getvar,
  113. NCDModule_handler_getobj handler_getobj,
  114. NCDModule_handler_initprocess handler_initprocess,
  115. BLog_logfunc logfunc)
  116. {
  117. // init arguments
  118. n->m = m;
  119. n->method_object = method_object;
  120. n->args = args;
  121. n->reactor = reactor;
  122. n->manager = manager;
  123. n->umanager = umanager;
  124. n->user = user;
  125. n->handler_event = handler_event;
  126. n->handler_getvar = handler_getvar;
  127. n->handler_getobj = handler_getobj;
  128. n->handler_initprocess = handler_initprocess;
  129. n->logfunc = logfunc;
  130. // init jobs
  131. BPending_Init(&n->init_job, BReactor_PendingGroup(n->reactor), (BPending_handler)init_job_handler, n);
  132. BPending_Init(&n->uninit_job, BReactor_PendingGroup(n->reactor), (BPending_handler)uninit_job_handler, n);
  133. BPending_Init(&n->die_job, BReactor_PendingGroup(n->reactor), (BPending_handler)die_job_handler, n);
  134. BPending_Init(&n->clean_job, BReactor_PendingGroup(n->reactor), (BPending_handler)clean_job_handler, n);
  135. // set initial state
  136. n->state = STATE_INIT;
  137. BPending_Set(&n->init_job);
  138. // set initial instance argument
  139. n->inst_user = NULL;
  140. // clear error flag
  141. n->is_error = 0;
  142. DebugObject_Init(&n->d_obj);
  143. }
  144. void NCDModuleInst_Free (NCDModuleInst *n)
  145. {
  146. DebugObject_Free(&n->d_obj);
  147. ASSERT(n->state == STATE_DEAD || n->state == STATE_UNDEAD)
  148. // free jobs
  149. BPending_Free(&n->clean_job);
  150. BPending_Free(&n->die_job);
  151. BPending_Free(&n->uninit_job);
  152. BPending_Free(&n->init_job);
  153. }
  154. void NCDModuleInst_Event (NCDModuleInst *n, int event)
  155. {
  156. DebugObject_Access(&n->d_obj);
  157. ASSERT(event == NCDMODULE_TOEVENT_DIE || event == NCDMODULE_TOEVENT_CLEAN)
  158. if (event == NCDMODULE_TOEVENT_DIE) {
  159. switch (n->state) {
  160. case STATE_INIT: {
  161. n->state = STATE_UNINIT;
  162. BPending_Unset(&n->init_job);
  163. BPending_Set(&n->uninit_job);
  164. } break;
  165. case STATE_DOWN_CLEAN:
  166. case STATE_DOWN_UNCLEAN: {
  167. n->state = STATE_DOWN_DIE;
  168. BPending_Set(&n->die_job);
  169. } break;
  170. case STATE_DOWN_PCLEAN: {
  171. n->state = STATE_DOWN_DIE;
  172. BPending_Unset(&n->clean_job);
  173. BPending_Set(&n->die_job);
  174. } break;
  175. case STATE_UP: {
  176. n->state = STATE_UP_DIE;
  177. BPending_Set(&n->die_job);
  178. } break;
  179. default: ASSERT(0);
  180. }
  181. }
  182. else if (event == NCDMODULE_TOEVENT_CLEAN) {
  183. switch (n->state) {
  184. case STATE_INIT:
  185. case STATE_DOWN_CLEAN:
  186. case STATE_DOWN_PCLEAN: {
  187. } break;
  188. case STATE_DOWN_UNCLEAN: {
  189. n->state = STATE_DOWN_PCLEAN;
  190. BPending_Set(&n->clean_job);
  191. } break;
  192. default: ASSERT(0);
  193. }
  194. }
  195. }
  196. int NCDModuleInst_GetVar (NCDModuleInst *n, const char *name, NCDValue *out)
  197. {
  198. DebugObject_Access(&n->d_obj);
  199. ASSERT(n->state == STATE_UP)
  200. ASSERT(name)
  201. if (!n->m->func_getvar) {
  202. return 0;
  203. }
  204. return n->m->func_getvar(n->inst_user, name, out);
  205. }
  206. NCDModuleInst * NCDModuleInst_GetObj (NCDModuleInst *n, const char *objname)
  207. {
  208. DebugObject_Access(&n->d_obj);
  209. ASSERT(n->state == STATE_UP)
  210. ASSERT(objname)
  211. if (!n->m->func_getobj) {
  212. return NULL;
  213. }
  214. return n->m->func_getobj(n->inst_user, objname);
  215. }
  216. int NCDModuleInst_HaveError (NCDModuleInst *n)
  217. {
  218. DebugObject_Access(&n->d_obj);
  219. ASSERT(n->state == STATE_DEAD || n->state == STATE_UNDEAD)
  220. return n->is_error;
  221. }
  222. void NCDModuleInst_Backend_SetUser (NCDModuleInst *n, void *user)
  223. {
  224. DebugObject_Access(&n->d_obj);
  225. ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
  226. n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
  227. n->state == STATE_DYING)
  228. n->inst_user = user;
  229. }
  230. void NCDModuleInst_Backend_Event (NCDModuleInst *n, int event)
  231. {
  232. DebugObject_Access(&n->d_obj);
  233. ASSERT(event == NCDMODULE_EVENT_UP || event == NCDMODULE_EVENT_DOWN || event == NCDMODULE_EVENT_DEAD)
  234. if (event == NCDMODULE_EVENT_UP) {
  235. switch (n->state) {
  236. case STATE_DOWN_CLEAN:
  237. case STATE_DOWN_UNCLEAN: {
  238. n->state = STATE_UP;
  239. frontend_event(n, NCDMODULE_EVENT_UP);
  240. } break;
  241. case STATE_DOWN_PCLEAN: {
  242. n->state = STATE_UP;
  243. BPending_Unset(&n->clean_job);
  244. frontend_event(n, NCDMODULE_EVENT_UP);
  245. } break;
  246. case STATE_DOWN_DIE: {
  247. n->state = STATE_UP_DIE;
  248. } break;
  249. default: ASSERT(0);
  250. }
  251. }
  252. else if (event == NCDMODULE_EVENT_DOWN) {
  253. switch (n->state) {
  254. case STATE_UP: {
  255. n->state = STATE_DOWN_UNCLEAN;
  256. frontend_event(n, NCDMODULE_EVENT_DOWN);
  257. } break;
  258. case STATE_UP_DIE: {
  259. n->state = STATE_DOWN_DIE;
  260. } break;
  261. default: ASSERT(0);
  262. }
  263. }
  264. else if (event == NCDMODULE_EVENT_DEAD) {
  265. switch (n->state) {
  266. case STATE_DOWN_DIE:
  267. case STATE_UP_DIE: {
  268. n->state = STATE_DEAD;
  269. BPending_Unset(&n->die_job);
  270. } break;
  271. case STATE_DOWN_CLEAN:
  272. case STATE_DOWN_UNCLEAN:
  273. case STATE_UP:
  274. case STATE_DYING: {
  275. n->state = STATE_DEAD;
  276. } break;
  277. case STATE_DOWN_PCLEAN: {
  278. n->state = STATE_DEAD;
  279. BPending_Unset(&n->clean_job);
  280. } break;
  281. default: ASSERT(0);
  282. }
  283. frontend_event(n, NCDMODULE_EVENT_DEAD);
  284. return;
  285. }
  286. }
  287. int NCDModuleInst_Backend_GetVar (NCDModuleInst *n, const char *varname, NCDValue *out)
  288. {
  289. DebugObject_Access(&n->d_obj);
  290. ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
  291. n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
  292. n->state == STATE_DYING)
  293. ASSERT(varname)
  294. int res = n->handler_getvar(n->user, varname, out);
  295. ASSERT(res == 0 || res == 1)
  296. return res;
  297. }
  298. NCDModuleInst * NCDModuleInst_Backend_GetObj (NCDModuleInst *n, const char *objname)
  299. {
  300. DebugObject_Access(&n->d_obj);
  301. ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
  302. n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
  303. n->state == STATE_DYING)
  304. ASSERT(objname)
  305. return n->handler_getobj(n->user, objname);
  306. }
  307. void NCDModuleInst_Backend_Log (NCDModuleInst *n, int channel, int level, const char *fmt, ...)
  308. {
  309. DebugObject_Access(&n->d_obj);
  310. va_list vl;
  311. va_start(vl, fmt);
  312. BLog_LogViaFuncVarArg(n->logfunc, n->user, channel, level, fmt, vl);
  313. va_end(vl);
  314. }
  315. void NCDModuleInst_Backend_SetError (NCDModuleInst *n)
  316. {
  317. DebugObject_Access(&n->d_obj);
  318. ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
  319. n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
  320. n->state == STATE_DYING)
  321. ASSERT(!n->is_error)
  322. n->is_error = 1;
  323. }
  324. int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValue args, void *user, NCDModuleProcess_handler_event handler_event)
  325. {
  326. DebugObject_Access(&n->d_obj);
  327. ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
  328. n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
  329. n->state == STATE_DYING)
  330. ASSERT(NCDValue_Type(&args) == NCDVALUE_LIST)
  331. ASSERT(handler_event)
  332. // init arguments
  333. o->n = n;
  334. o->user = user;
  335. o->handler_event = handler_event;
  336. // init event job
  337. BPending_Init(&o->event_job, BReactor_PendingGroup(n->reactor), (BPending_handler)process_event_job_handler, o);
  338. // set state
  339. o->state = PROCESS_STATE_INIT;
  340. // clear event func so we can assert it was set
  341. o->interp_func_event = NULL;
  342. // init interpreter part
  343. if (!(n->handler_initprocess(n->user, o, template_name, args))) {
  344. goto fail1;
  345. }
  346. ASSERT(o->interp_func_event)
  347. // set state
  348. o->state = PROCESS_STATE_DOWN;
  349. DebugObject_Init(&o->d_obj);
  350. return 1;
  351. fail1:
  352. BPending_Free(&o->event_job);
  353. return 0;
  354. }
  355. void NCDModuleProcess_Free (NCDModuleProcess *o)
  356. {
  357. DebugObject_Free(&o->d_obj);
  358. ASSERT(o->state == PROCESS_STATE_TERMINATED)
  359. // free event job
  360. BPending_Free(&o->event_job);
  361. }
  362. void NCDModuleProcess_Continue (NCDModuleProcess *o)
  363. {
  364. DebugObject_Access(&o->d_obj);
  365. ASSERT(o->state == PROCESS_STATE_DOWN_WAITING)
  366. o->state = PROCESS_STATE_DOWN;
  367. o->interp_func_event(o->interp_user, NCDMODULEPROCESS_INTERP_EVENT_CONTINUE);
  368. }
  369. void NCDModuleProcess_Terminate (NCDModuleProcess *o)
  370. {
  371. DebugObject_Access(&o->d_obj);
  372. ASSERT(o->state == PROCESS_STATE_DOWN || o->state == PROCESS_STATE_UP_PENDING ||
  373. o->state == PROCESS_STATE_DOWN_CONTINUE_PENDING || o->state == PROCESS_STATE_UP ||
  374. o->state == PROCESS_STATE_DOWN_PENDING || o->state == PROCESS_STATE_DOWN_WAITING)
  375. BPending_Unset(&o->event_job);
  376. o->state = PROCESS_STATE_TERMINATING;
  377. o->interp_func_event(o->interp_user, NCDMODULEPROCESS_INTERP_EVENT_TERMINATE);
  378. }
  379. int NCDModuleProcess_GetVar (NCDModuleProcess *o, const char *name, NCDValue *out)
  380. {
  381. DebugObject_Access(&o->d_obj);
  382. ASSERT(o->state != PROCESS_STATE_INIT)
  383. ASSERT(name)
  384. ASSERT(out)
  385. // interpreter gone?
  386. if (o->state == PROCESS_STATE_TERMINATED_PENDING || o->state == PROCESS_STATE_TERMINATED) {
  387. return 0;
  388. }
  389. int res = o->interp_func_getvar(o->interp_user, name, out);
  390. ASSERT(res == 0 || res == 1)
  391. return res;
  392. }
  393. NCDModuleInst * NCDModuleProcess_GetObj (NCDModuleProcess *o, const char *name)
  394. {
  395. DebugObject_Access(&o->d_obj);
  396. ASSERT(o->state != PROCESS_STATE_INIT)
  397. ASSERT(name)
  398. // interpreter gone?
  399. if (o->state == PROCESS_STATE_TERMINATED_PENDING || o->state == PROCESS_STATE_TERMINATED) {
  400. return NULL;
  401. }
  402. return o->interp_func_getobj(o->interp_user, name);
  403. }
  404. void NCDModuleProcess_Interp_SetHandlers (NCDModuleProcess *o, void *interp_user,
  405. NCDModuleProcess_interp_func_event interp_func_event,
  406. NCDModuleProcess_interp_func_getvar interp_func_getvar,
  407. NCDModuleProcess_interp_func_getobj interp_func_getobj)
  408. {
  409. ASSERT(interp_func_event)
  410. ASSERT(interp_func_getvar)
  411. ASSERT(interp_func_getobj)
  412. o->interp_user = interp_user;
  413. o->interp_func_event = interp_func_event;
  414. o->interp_func_getvar = interp_func_getvar;
  415. o->interp_func_getobj = interp_func_getobj;
  416. }
  417. void NCDModuleProcess_Interp_Up (NCDModuleProcess *o)
  418. {
  419. DebugObject_Access(&o->d_obj);
  420. ASSERT(o->state == PROCESS_STATE_DOWN)
  421. BPending_Set(&o->event_job);
  422. o->state = PROCESS_STATE_UP_PENDING;
  423. }
  424. void NCDModuleProcess_Interp_Down (NCDModuleProcess *o)
  425. {
  426. DebugObject_Access(&o->d_obj);
  427. switch (o->state) {
  428. case PROCESS_STATE_UP_PENDING: {
  429. BPending_Unset(&o->event_job);
  430. BPending_Set(&o->event_job);
  431. o->state = PROCESS_STATE_DOWN_CONTINUE_PENDING;
  432. } break;
  433. case PROCESS_STATE_UP: {
  434. BPending_Set(&o->event_job);
  435. o->state = PROCESS_STATE_DOWN_PENDING;
  436. } break;
  437. default: ASSERT(0);
  438. }
  439. }
  440. void NCDModuleProcess_Interp_Terminated (NCDModuleProcess *o)
  441. {
  442. DebugObject_Access(&o->d_obj);
  443. ASSERT(o->state == PROCESS_STATE_TERMINATING)
  444. BPending_Set(&o->event_job);
  445. o->state = PROCESS_STATE_TERMINATED_PENDING;
  446. }