ncd.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. /**
  2. * @file ncd.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 <stdint.h>
  23. #include <stdio.h>
  24. #include <stddef.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <misc/version.h>
  28. #include <misc/loggers_string.h>
  29. #include <misc/loglevel.h>
  30. #include <misc/offset.h>
  31. #include <misc/read_file.h>
  32. #include <misc/balloc.h>
  33. #include <structure/LinkedList2.h>
  34. #include <system/BLog.h>
  35. #include <system/BReactor.h>
  36. #include <system/BProcess.h>
  37. #include <system/BSignal.h>
  38. #include <system/BSocket.h>
  39. #include <ncdconfig/NCDConfigParser.h>
  40. #include <ncd/NCDModule.h>
  41. #include <ncd/modules/modules.h>
  42. #ifndef BADVPN_USE_WINAPI
  43. #include <system/BLog_syslog.h>
  44. #endif
  45. #include <ncd/ncd.h>
  46. #include <generated/blog_channel_ncd.h>
  47. #define LOGGER_STDOUT 1
  48. #define LOGGER_SYSLOG 2
  49. #define SSTATE_CHILD 1
  50. #define SSTATE_ADULT 2
  51. #define SSTATE_DYING 3
  52. #define SSTATE_FORGOTTEN 4
  53. struct statement {
  54. const struct NCDModule *module;
  55. struct argument_elem *first_arg;
  56. char *name;
  57. };
  58. struct argument_elem {
  59. int is_var;
  60. union {
  61. struct {
  62. char *modname;
  63. char *varname;
  64. } var;
  65. NCDValue val;
  66. };
  67. struct argument_elem *next_arg;
  68. };
  69. struct process {
  70. char *name;
  71. size_t num_statements;
  72. struct process_statement *statements;
  73. size_t ap;
  74. size_t fp;
  75. BTimer wait_timer;
  76. LinkedList2Node list_node; // node in processes
  77. };
  78. struct process_statement {
  79. struct process *p;
  80. size_t i;
  81. struct statement s;
  82. int state;
  83. int have_error;
  84. btime_t error_until;
  85. NCDModuleInst inst;
  86. NCDValue inst_args;
  87. char logprefix[50];
  88. };
  89. // command-line options
  90. struct {
  91. int help;
  92. int version;
  93. int logger;
  94. #ifndef BADVPN_USE_WINAPI
  95. char *logger_syslog_facility;
  96. char *logger_syslog_ident;
  97. #endif
  98. int loglevel;
  99. int loglevels[BLOG_NUM_CHANNELS];
  100. char *config_file;
  101. } options;
  102. // reactor
  103. BReactor ss;
  104. // are we terminating
  105. int terminating;
  106. // process manager
  107. BProcessManager manager;
  108. // configuration
  109. struct NCDConfig_interfaces *configuration;
  110. // processes
  111. LinkedList2 processes;
  112. // job for initializing processes
  113. BPending init_job;
  114. // next process for init job
  115. struct NCDConfig_interfaces *init_next;
  116. // job for initiating shutdown of processes
  117. BPending free_job;
  118. // process iterator for free job
  119. LinkedList2Iterator free_it;
  120. static void terminate (void);
  121. static void print_help (const char *name);
  122. static void print_version (void);
  123. static int parse_arguments (int argc, char *argv[]);
  124. static void signal_handler (void *unused);
  125. static const struct NCDModule * find_module (const char *name);
  126. static int statement_init (struct statement *s, struct NCDConfig_statements *conf);
  127. static void statement_free (struct statement *s);
  128. static void statement_free_args (struct statement *s);
  129. static int process_new (struct NCDConfig_interfaces *conf);
  130. static void process_free (struct process *p);
  131. static void process_free_statements (struct process *p);
  132. static void process_assert_pointers (struct process *p);
  133. static void process_assert (struct process *p);
  134. static void process_log (struct process *p, int level, const char *fmt, ...);
  135. static void process_work (struct process *p);
  136. static void process_fight (struct process *p);
  137. static void process_advance (struct process *p);
  138. static void process_wait (struct process *p);
  139. static void process_wait_timer_handler (struct process *p);
  140. static void process_retreat (struct process *p);
  141. static void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...);
  142. static void process_statement_set_error (struct process_statement *ps);
  143. static void process_statement_instance_handler_event (struct process_statement *ps, int event);
  144. static void process_statement_instance_handler_died (struct process_statement *ps, int is_error);
  145. static void init_job_handler (void *unused);
  146. static void free_job_handler (void *unused);
  147. int main (int argc, char **argv)
  148. {
  149. if (argc <= 0) {
  150. return 1;
  151. }
  152. // parse command-line arguments
  153. if (!parse_arguments(argc, argv)) {
  154. fprintf(stderr, "Failed to parse arguments\n");
  155. print_help(argv[0]);
  156. goto fail0;
  157. }
  158. // handle --help and --version
  159. if (options.help) {
  160. print_version();
  161. print_help(argv[0]);
  162. return 0;
  163. }
  164. if (options.version) {
  165. print_version();
  166. return 0;
  167. }
  168. // initialize logger
  169. switch (options.logger) {
  170. case LOGGER_STDOUT:
  171. BLog_InitStdout();
  172. break;
  173. #ifndef BADVPN_USE_WINAPI
  174. case LOGGER_SYSLOG:
  175. if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) {
  176. fprintf(stderr, "Failed to initialize syslog logger\n");
  177. goto fail0;
  178. }
  179. break;
  180. #endif
  181. default:
  182. ASSERT(0);
  183. }
  184. // configure logger channels
  185. for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
  186. if (options.loglevels[i] >= 0) {
  187. BLog_SetChannelLoglevel(i, options.loglevels[i]);
  188. }
  189. else if (options.loglevel >= 0) {
  190. BLog_SetChannelLoglevel(i, options.loglevel);
  191. }
  192. }
  193. BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
  194. // initialize sockets
  195. if (BSocket_GlobalInit() < 0) {
  196. BLog(BLOG_ERROR, "BSocket_GlobalInit failed");
  197. goto fail1;
  198. }
  199. // init time
  200. BTime_Init();
  201. // init reactor
  202. if (!BReactor_Init(&ss)) {
  203. BLog(BLOG_ERROR, "BReactor_Init failed");
  204. goto fail1;
  205. }
  206. // set not terminating
  207. terminating = 0;
  208. // init process manager
  209. if (!BProcessManager_Init(&manager, &ss)) {
  210. BLog(BLOG_ERROR, "BProcessManager_Init failed");
  211. goto fail1a;
  212. }
  213. // setup signal handler
  214. if (!BSignal_Init(&ss, signal_handler, NULL)) {
  215. BLog(BLOG_ERROR, "BSignal_Init failed");
  216. goto fail2;
  217. }
  218. // read config file
  219. uint8_t *file;
  220. size_t file_len;
  221. if (!read_file(options.config_file, &file, &file_len)) {
  222. BLog(BLOG_ERROR, "failed to read config file");
  223. goto fail3;
  224. }
  225. // parse config file
  226. if (!NCDConfigParser_Parse((char *)file, file_len, &configuration)) {
  227. BLog(BLOG_ERROR, "NCDConfigParser_Parse failed");
  228. free(file);
  229. goto fail3;
  230. }
  231. // fee config file memory
  232. free(file);
  233. // init modules
  234. for (const struct NCDModuleGroup **g = ncd_modules; *g; g++) {
  235. if ((*g)->func_globalinit && !(*g)->func_globalinit()) {
  236. BLog(BLOG_ERROR, "globalinit failed for some module");
  237. goto fail5;
  238. }
  239. }
  240. // init processes list
  241. LinkedList2_Init(&processes);
  242. // init init job
  243. BPending_Init(&init_job, BReactor_PendingGroup(&ss), init_job_handler, NULL);
  244. // init free job
  245. BPending_Init(&free_job, BReactor_PendingGroup(&ss), free_job_handler, NULL);
  246. // start initializing processes
  247. init_next = configuration;
  248. BPending_Set(&init_job);
  249. // enter event loop
  250. BLog(BLOG_NOTICE, "entering event loop");
  251. BReactor_Exec(&ss);
  252. // free processes
  253. LinkedList2Node *n;
  254. while (n = LinkedList2_GetFirst(&processes)) {
  255. struct process *p = UPPER_OBJECT(n, struct process, list_node);
  256. process_free(p);
  257. }
  258. // free free job
  259. BPending_Free(&free_job);
  260. // free init job
  261. BPending_Free(&init_job);
  262. fail5:
  263. // free configuration
  264. NCDConfig_free_interfaces(configuration);
  265. fail3:
  266. // remove signal handler
  267. BSignal_Finish();
  268. fail2:
  269. // free process manager
  270. BProcessManager_Free(&manager);
  271. fail1a:
  272. // free reactor
  273. BReactor_Free(&ss);
  274. fail1:
  275. // free logger
  276. BLog(BLOG_NOTICE, "exiting");
  277. BLog_Free();
  278. fail0:
  279. // finish objects
  280. DebugObjectGlobal_Finish();
  281. return 1;
  282. }
  283. void terminate (void)
  284. {
  285. ASSERT(!terminating)
  286. BLog(BLOG_NOTICE, "tearing down");
  287. terminating = 1;
  288. if (LinkedList2_IsEmpty(&processes)) {
  289. BReactor_Quit(&ss, 1);
  290. return;
  291. }
  292. // start free job
  293. LinkedList2Iterator_InitForward(&free_it, &processes);
  294. BPending_Set(&free_job);
  295. }
  296. void print_help (const char *name)
  297. {
  298. printf(
  299. "Usage:\n"
  300. " %s\n"
  301. " [--help]\n"
  302. " [--version]\n"
  303. " [--logger <"LOGGERS_STRING">]\n"
  304. #ifndef BADVPN_USE_WINAPI
  305. " (logger=syslog?\n"
  306. " [--syslog-facility <string>]\n"
  307. " [--syslog-ident <string>]\n"
  308. " )\n"
  309. #endif
  310. " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
  311. " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
  312. " --config-file <file>\n",
  313. name
  314. );
  315. }
  316. void print_version (void)
  317. {
  318. printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
  319. }
  320. int parse_arguments (int argc, char *argv[])
  321. {
  322. if (argc <= 0) {
  323. return 0;
  324. }
  325. options.help = 0;
  326. options.version = 0;
  327. options.logger = LOGGER_STDOUT;
  328. #ifndef BADVPN_USE_WINAPI
  329. options.logger_syslog_facility = "daemon";
  330. options.logger_syslog_ident = argv[0];
  331. #endif
  332. options.loglevel = -1;
  333. for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
  334. options.loglevels[i] = -1;
  335. }
  336. options.config_file = NULL;
  337. for (int i = 1; i < argc; i++) {
  338. char *arg = argv[i];
  339. if (!strcmp(arg, "--help")) {
  340. options.help = 1;
  341. }
  342. else if (!strcmp(arg, "--version")) {
  343. options.version = 1;
  344. }
  345. else if (!strcmp(arg, "--logger")) {
  346. if (1 >= argc - i) {
  347. fprintf(stderr, "%s: requires an argument\n", arg);
  348. return 0;
  349. }
  350. char *arg2 = argv[i + 1];
  351. if (!strcmp(arg2, "stdout")) {
  352. options.logger = LOGGER_STDOUT;
  353. }
  354. #ifndef BADVPN_USE_WINAPI
  355. else if (!strcmp(arg2, "syslog")) {
  356. options.logger = LOGGER_SYSLOG;
  357. }
  358. #endif
  359. else {
  360. fprintf(stderr, "%s: wrong argument\n", arg);
  361. return 0;
  362. }
  363. i++;
  364. }
  365. #ifndef BADVPN_USE_WINAPI
  366. else if (!strcmp(arg, "--syslog-facility")) {
  367. if (1 >= argc - i) {
  368. fprintf(stderr, "%s: requires an argument\n", arg);
  369. return 0;
  370. }
  371. options.logger_syslog_facility = argv[i + 1];
  372. i++;
  373. }
  374. else if (!strcmp(arg, "--syslog-ident")) {
  375. if (1 >= argc - i) {
  376. fprintf(stderr, "%s: requires an argument\n", arg);
  377. return 0;
  378. }
  379. options.logger_syslog_ident = argv[i + 1];
  380. i++;
  381. }
  382. #endif
  383. else if (!strcmp(arg, "--loglevel")) {
  384. if (1 >= argc - i) {
  385. fprintf(stderr, "%s: requires an argument\n", arg);
  386. return 0;
  387. }
  388. if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
  389. fprintf(stderr, "%s: wrong argument\n", arg);
  390. return 0;
  391. }
  392. i++;
  393. }
  394. else if (!strcmp(arg, "--channel-loglevel")) {
  395. if (2 >= argc - i) {
  396. fprintf(stderr, "%s: requires two arguments\n", arg);
  397. return 0;
  398. }
  399. int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
  400. if (channel < 0) {
  401. fprintf(stderr, "%s: wrong channel argument\n", arg);
  402. return 0;
  403. }
  404. int loglevel = parse_loglevel(argv[i + 2]);
  405. if (loglevel < 0) {
  406. fprintf(stderr, "%s: wrong loglevel argument\n", arg);
  407. return 0;
  408. }
  409. options.loglevels[channel] = loglevel;
  410. i += 2;
  411. }
  412. else if (!strcmp(arg, "--config-file")) {
  413. if (1 >= argc - i) {
  414. fprintf(stderr, "%s: requires an argument\n", arg);
  415. return 0;
  416. }
  417. options.config_file = argv[i + 1];
  418. i++;
  419. }
  420. else {
  421. fprintf(stderr, "unknown option: %s\n", arg);
  422. return 0;
  423. }
  424. }
  425. if (options.help || options.version) {
  426. return 1;
  427. }
  428. if (!options.config_file) {
  429. fprintf(stderr, "--config-file is required\n");
  430. return 0;
  431. }
  432. return 1;
  433. }
  434. void signal_handler (void *unused)
  435. {
  436. BLog(BLOG_NOTICE, "termination requested");
  437. if (!terminating) {
  438. terminate();
  439. }
  440. }
  441. const struct NCDModule * find_module (const char *name)
  442. {
  443. for (const struct NCDModuleGroup **g = ncd_modules; *g; g++) {
  444. for (const struct NCDModule *m = (*g)->modules; m->type; m++) {
  445. if (!strcmp(m->type, name)) {
  446. return m;
  447. }
  448. }
  449. }
  450. return NULL;
  451. }
  452. int statement_init (struct statement *s, struct NCDConfig_statements *conf)
  453. {
  454. // find module
  455. char *module_name = NCDConfig_concat_strings(conf->names);
  456. if (!module_name) {
  457. goto fail0;
  458. }
  459. const struct NCDModule *m = find_module(module_name);
  460. if (!m) {
  461. BLog(BLOG_ERROR, "no module for statement %s", module_name);
  462. free(module_name);
  463. goto fail0;
  464. }
  465. free(module_name);
  466. // set module
  467. s->module = m;
  468. // init arguments
  469. s->first_arg = NULL;
  470. struct argument_elem **prevptr = &s->first_arg;
  471. struct NCDConfig_arguments *arg = conf->args;
  472. while (arg) {
  473. struct argument_elem *e = malloc(sizeof(*e));
  474. if (!e) {
  475. goto fail1;
  476. }
  477. switch (arg->type) {
  478. case NCDCONFIG_ARG_STRING: {
  479. if (!NCDValue_InitString(&e->val, arg->string)) {
  480. free(e);
  481. goto fail1;
  482. }
  483. e->is_var = 0;
  484. } break;
  485. case NCDCONFIG_ARG_VAR: {
  486. if (!(e->var.modname = strdup(arg->var->value))) {
  487. free(e);
  488. goto fail1;
  489. }
  490. if (!arg->var->next) {
  491. e->var.varname = NULL;
  492. } else {
  493. if (!(e->var.varname = NCDConfig_concat_strings(arg->var->next))) {
  494. free(e->var.modname);
  495. free(e);
  496. goto fail1;
  497. }
  498. }
  499. e->is_var = 1;
  500. } break;
  501. default:
  502. ASSERT(0);
  503. }
  504. *prevptr = e;
  505. e->next_arg = NULL;
  506. prevptr = &e->next_arg;
  507. arg = arg->next;
  508. }
  509. // init name
  510. if (!conf->name) {
  511. s->name = NULL;
  512. } else {
  513. if (!(s->name = strdup(conf->name))) {
  514. goto fail1;
  515. }
  516. }
  517. return 1;
  518. fail1:
  519. statement_free_args(s);
  520. fail0:
  521. return 0;
  522. }
  523. void statement_free (struct statement *s)
  524. {
  525. // free name
  526. free(s->name);
  527. // free arguments
  528. statement_free_args(s);
  529. }
  530. void statement_free_args (struct statement *s)
  531. {
  532. struct argument_elem *e = s->first_arg;
  533. while (e) {
  534. if (e->is_var) {
  535. free(e->var.modname);
  536. free(e->var.varname);
  537. } else {
  538. NCDValue_Free(&e->val);
  539. }
  540. struct argument_elem *n = e->next_arg;
  541. free(e);
  542. e = n;
  543. }
  544. }
  545. int process_new (struct NCDConfig_interfaces *conf)
  546. {
  547. // allocate strucure
  548. struct process *p = malloc(sizeof(*p));
  549. if (!p) {
  550. goto fail0;
  551. }
  552. // init name
  553. if (!(p->name = strdup(conf->name))) {
  554. goto fail1;
  555. }
  556. // count statements
  557. size_t num_st = 0;
  558. struct NCDConfig_statements *st = conf->statements;
  559. while (st) {
  560. num_st++;
  561. st = st->next;
  562. }
  563. // statements array
  564. if (!(p->statements = BAllocArray(num_st, sizeof(p->statements[0])))) {
  565. goto fail2;
  566. }
  567. p->num_statements = 0;
  568. // init statements
  569. st = conf->statements;
  570. while (st) {
  571. struct process_statement *ps = &p->statements[p->num_statements];
  572. ps->p = p;
  573. ps->i = p->num_statements;
  574. if (!statement_init(&ps->s, st)) {
  575. goto fail3;
  576. }
  577. ps->state = SSTATE_FORGOTTEN;
  578. ps->have_error = 0;
  579. p->num_statements++;
  580. st = st->next;
  581. }
  582. // set AP=0
  583. p->ap = 0;
  584. // set FP=0
  585. p->fp = 0;
  586. // init timer
  587. BTimer_Init(&p->wait_timer, RETRY_TIME, (BTimer_handler)process_wait_timer_handler, p);
  588. // insert to processes list
  589. LinkedList2_Append(&processes, &p->list_node);
  590. process_work(p);
  591. return 1;
  592. fail3:
  593. process_free_statements(p);
  594. fail2:
  595. free(p->name);
  596. fail1:
  597. free(p);
  598. fail0:
  599. return 0;
  600. }
  601. void process_free (struct process *p)
  602. {
  603. ASSERT(p->ap == 0)
  604. ASSERT(p->fp == 0)
  605. // remove from processes list
  606. LinkedList2_Remove(&processes, &p->list_node);
  607. // free timer
  608. BReactor_RemoveTimer(&ss, &p->wait_timer);
  609. // free statements
  610. process_free_statements(p);
  611. // free name
  612. free(p->name);
  613. // free strucure
  614. free(p);
  615. }
  616. void process_free_statements (struct process *p)
  617. {
  618. // free statments
  619. for (size_t i = 0; i < p->num_statements; i++) {
  620. struct process_statement *ps = &p->statements[i];
  621. statement_free(&ps->s);
  622. }
  623. // free stataments array
  624. free(p->statements);
  625. }
  626. void process_assert_pointers (struct process *p)
  627. {
  628. ASSERT(p->ap <= p->num_statements)
  629. ASSERT(p->fp >= p->ap)
  630. ASSERT(p->fp <= p->num_statements)
  631. // check AP
  632. for (size_t i = 0; i < p->ap; i++) {
  633. if (i == p->ap - 1) {
  634. ASSERT(p->statements[i].state == SSTATE_ADULT || p->statements[i].state == SSTATE_CHILD)
  635. } else {
  636. ASSERT(p->statements[i].state == SSTATE_ADULT)
  637. }
  638. }
  639. // check FP
  640. size_t fp = p->num_statements;
  641. while (fp > 0 && p->statements[fp - 1].state == SSTATE_FORGOTTEN) {
  642. fp--;
  643. }
  644. ASSERT(p->fp == fp)
  645. }
  646. void process_assert (struct process *p)
  647. {
  648. process_assert_pointers(p);
  649. }
  650. void process_log (struct process *p, int level, const char *fmt, ...)
  651. {
  652. va_list vl;
  653. va_start(vl, fmt);
  654. BLog_Append("process %s: ", p->name);
  655. BLog_LogToChannelVarArg(BLOG_CURRENT_CHANNEL, level, fmt, vl);
  656. va_end(vl);
  657. }
  658. void process_work (struct process *p)
  659. {
  660. process_assert_pointers(p);
  661. // stop timer in case we were WAITING
  662. BReactor_RemoveTimer(&ss, &p->wait_timer);
  663. if (terminating) {
  664. process_retreat(p);
  665. return;
  666. }
  667. process_fight(p);
  668. }
  669. void process_fight (struct process *p)
  670. {
  671. if (p->ap == p->fp) {
  672. if (!(p->ap > 0 && p->statements[p->ap - 1].state == SSTATE_CHILD)) {
  673. // advance
  674. process_advance(p);
  675. }
  676. return;
  677. }
  678. // order the last living statement to die, if needed
  679. struct process_statement *ps = &p->statements[p->fp - 1];
  680. if (ps->state != SSTATE_DYING) {
  681. process_statement_log(ps, BLOG_INFO, "killing");
  682. // order it to die
  683. NCDModuleInst_Die(&ps->inst);
  684. // set statement state DYING
  685. ps->state = SSTATE_DYING;
  686. }
  687. process_assert(p);
  688. }
  689. void process_advance (struct process *p)
  690. {
  691. ASSERT(p->ap == p->fp)
  692. ASSERT(!(p->ap > 0) || p->statements[p->ap - 1].state == SSTATE_ADULT)
  693. if (p->ap == p->num_statements) {
  694. process_log(p, BLOG_INFO, "victory");
  695. process_assert(p);
  696. return;
  697. }
  698. struct process_statement *ps = &p->statements[p->ap];
  699. // check if we need to wait
  700. if (ps->have_error && ps->error_until > btime_gettime()) {
  701. process_wait(p);
  702. return;
  703. }
  704. process_statement_log(ps, BLOG_INFO, "initializing");
  705. // init arguments list
  706. NCDValue_InitList(&ps->inst_args);
  707. // build arguments
  708. struct argument_elem *arg = ps->s.first_arg;
  709. while (arg) {
  710. NCDValue v;
  711. if (arg->is_var) {
  712. // find referred-to statement
  713. struct process_statement *rps;
  714. size_t i;
  715. for (i = p->ap; i > 0; i--) {
  716. rps = &p->statements[i - 1];
  717. if (rps->s.name && !strcmp(rps->s.name, arg->var.modname)) {
  718. break;
  719. }
  720. }
  721. if (i == 0) {
  722. process_statement_log(ps, BLOG_ERROR, "unknown statement name in variable: %s.%s", arg->var.modname, arg->var.varname);
  723. goto fail1;
  724. }
  725. ASSERT(rps->state == SSTATE_ADULT)
  726. // resolve variable
  727. const char *real_varname = (arg->var.varname ? arg->var.varname : "");
  728. if (!NCDModuleInst_GetVar(&rps->inst, real_varname, &v)) {
  729. process_statement_log(ps, BLOG_ERROR, "failed to resolve variable: %s.%s", arg->var.modname, real_varname);
  730. goto fail1;
  731. }
  732. } else {
  733. if (!NCDValue_InitCopy(&v, &arg->val)) {
  734. process_statement_log(ps, BLOG_ERROR, "NCDValue_InitCopy failed");
  735. goto fail1;
  736. }
  737. }
  738. // move to list
  739. if (!NCDValue_ListAppend(&ps->inst_args, v)) {
  740. process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
  741. NCDValue_Free(&v);
  742. goto fail1;
  743. }
  744. arg = arg->next_arg;
  745. }
  746. // generate log prefix
  747. snprintf(ps->logprefix, sizeof(ps->logprefix), "process %s: statement %zu: module: ", p->name, ps->i);
  748. // initialize module instance
  749. if (!NCDModuleInst_Init(
  750. &ps->inst, ps->s.name, ps->s.module, &ps->inst_args, ps->logprefix, &ss, &manager,
  751. (NCDModule_handler_event)process_statement_instance_handler_event, (NCDModule_handler_died)process_statement_instance_handler_died, ps
  752. )) {
  753. process_statement_log(ps, BLOG_ERROR, "failed to initialize");
  754. goto fail1;
  755. }
  756. // set statement state CHILD
  757. ps->state = SSTATE_CHILD;
  758. // increment AP
  759. p->ap++;
  760. // increment FP
  761. p->fp++;
  762. process_assert(p);
  763. return;
  764. fail1:
  765. NCDValue_Free(&ps->inst_args);
  766. process_statement_set_error(ps);
  767. process_wait(p);
  768. }
  769. void process_wait (struct process *p)
  770. {
  771. ASSERT(p->ap == p->fp)
  772. ASSERT(!(p->ap > 0) || p->statements[p->ap - 1].state == SSTATE_ADULT)
  773. ASSERT(p->ap < p->num_statements)
  774. ASSERT(p->statements[p->ap].have_error)
  775. process_statement_log(&p->statements[p->ap], BLOG_INFO, "waiting after error");
  776. // set timer
  777. BReactor_SetTimerAbsolute(&ss, &p->wait_timer, p->statements[p->ap].error_until);
  778. process_assert(p);
  779. }
  780. void process_wait_timer_handler (struct process *p)
  781. {
  782. ASSERT(p->ap == p->fp)
  783. ASSERT(!(p->ap > 0) || p->statements[p->ap - 1].state == SSTATE_ADULT)
  784. ASSERT(p->ap < p->num_statements)
  785. ASSERT(p->statements[p->ap].have_error)
  786. process_log(p, BLOG_INFO, "retrying");
  787. // clear error
  788. p->statements[p->ap].have_error = 0;
  789. process_advance(p);
  790. }
  791. void process_retreat (struct process *p)
  792. {
  793. if (p->fp == 0) {
  794. // finished retreating
  795. process_free(p);
  796. // if there are no more processes, exit program
  797. if (LinkedList2_IsEmpty(&processes)) {
  798. BReactor_Quit(&ss, 1);
  799. }
  800. return;
  801. }
  802. // order the last living statement to die, if needed
  803. struct process_statement *ps = &p->statements[p->fp - 1];
  804. if (ps->state != SSTATE_DYING) {
  805. process_statement_log(ps, BLOG_INFO, "killing");
  806. // order it to die
  807. NCDModuleInst_Die(&ps->inst);
  808. // set statement state DYING
  809. ps->state = SSTATE_DYING;
  810. // update AP
  811. if (p->ap > ps->i) {
  812. p->ap = ps->i;
  813. }
  814. }
  815. process_assert(p);
  816. }
  817. void process_statement_log (struct process_statement *ps, int level, const char *fmt, ...)
  818. {
  819. va_list vl;
  820. va_start(vl, fmt);
  821. BLog_Append("process %s: statement %zu: ", ps->p->name, ps->i);
  822. BLog_LogToChannelVarArg(BLOG_CURRENT_CHANNEL, level, fmt, vl);
  823. va_end(vl);
  824. }
  825. void process_statement_set_error (struct process_statement *ps)
  826. {
  827. ASSERT(ps->state == SSTATE_FORGOTTEN)
  828. ps->have_error = 1;
  829. ps->error_until = btime_gettime() + RETRY_TIME;
  830. }
  831. void process_statement_instance_handler_event (struct process_statement *ps, int event)
  832. {
  833. ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT)
  834. struct process *p = ps->p;
  835. switch (event) {
  836. case NCDMODULE_EVENT_UP: {
  837. ASSERT(ps->state == SSTATE_CHILD)
  838. process_statement_log(ps, BLOG_INFO, "up");
  839. // set state ADULT
  840. ps->state = SSTATE_ADULT;
  841. } break;
  842. case NCDMODULE_EVENT_DOWN: {
  843. ASSERT(ps->state == SSTATE_ADULT)
  844. process_statement_log(ps, BLOG_INFO, "down");
  845. // set state CHILD
  846. ps->state = SSTATE_CHILD;
  847. // update AP
  848. if (p->ap > ps->i + 1) {
  849. p->ap = ps->i + 1;
  850. }
  851. } break;
  852. case NCDMODULE_EVENT_DYING: {
  853. ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT)
  854. process_statement_log(ps, BLOG_INFO, "dying");
  855. // set state DYING
  856. ps->state = SSTATE_DYING;
  857. // update AP
  858. if (p->ap > ps->i) {
  859. p->ap = ps->i;
  860. }
  861. } break;
  862. }
  863. process_work(p);
  864. return;
  865. }
  866. void process_statement_instance_handler_died (struct process_statement *ps, int is_error)
  867. {
  868. ASSERT(ps->state == SSTATE_CHILD || ps->state == SSTATE_ADULT || ps->state == SSTATE_DYING)
  869. struct process *p = ps->p;
  870. // free instance
  871. NCDModuleInst_Free(&ps->inst);
  872. // free instance arguments
  873. NCDValue_Free(&ps->inst_args);
  874. // set state FORGOTTEN
  875. ps->state = SSTATE_FORGOTTEN;
  876. // set error
  877. if (is_error) {
  878. process_statement_set_error(ps);
  879. } else {
  880. ps->have_error = 0;
  881. }
  882. // update AP
  883. if (p->ap > ps->i) {
  884. p->ap = ps->i;
  885. }
  886. // update FP
  887. while (p->fp > 0 && p->statements[p->fp - 1].state == SSTATE_FORGOTTEN) {
  888. p->fp--;
  889. }
  890. process_statement_log(ps, BLOG_INFO, "died");
  891. if (is_error) {
  892. process_statement_log(ps, BLOG_ERROR, "with error");
  893. }
  894. process_work(p);
  895. return;
  896. }
  897. void init_job_handler (void *unused)
  898. {
  899. ASSERT(!terminating)
  900. if (!init_next) {
  901. // initialized all processes
  902. return;
  903. }
  904. struct NCDConfig_interfaces *conf = init_next;
  905. // schedule next
  906. init_next = init_next->next;
  907. BPending_Set(&init_job);
  908. // init process
  909. process_new(conf);
  910. }
  911. void free_job_handler (void *unused)
  912. {
  913. ASSERT(terminating)
  914. LinkedList2Node *n = LinkedList2Iterator_Next(&free_it);
  915. if (!n) {
  916. // done initiating shutdown for all processes
  917. return;
  918. }
  919. struct process *p = UPPER_OBJECT(n, struct process, list_node);
  920. // schedule next
  921. BPending_Set(&free_job);
  922. process_work(p);
  923. return;
  924. }