blocker.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /**
  2. * @file blocker.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. * @section DESCRIPTION
  23. *
  24. * Blocker module. Provides a statement that blocks when initialized, and which can be blocked
  25. * and unblocked from outside.
  26. *
  27. * Synopsis: blocker()
  28. * Description: provides blocking operations. Initially the blocking state is down (but this statement
  29. * does not block).
  30. *
  31. * Synopsis: blocker::up()
  32. * Description: sets the blocking state to up.
  33. *
  34. * Synopsis: blocker::down()
  35. * Description: sets the blocking state to down.
  36. *
  37. * Synopsis: blocker::use()
  38. * Description: blocks on the blocker. This module is in up state if and only if the blocking state of
  39. * the blocker is up. Multiple use statements may be used with the same blocker.
  40. */
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <misc/offset.h>
  44. #include <misc/debug.h>
  45. #include <ncd/NCDModule.h>
  46. #include <generated/blog_channel_ncd_blocker.h>
  47. #define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
  48. struct instance {
  49. NCDModuleInst *i;
  50. LinkedList2 users;
  51. int up;
  52. int dying;
  53. };
  54. struct updown_instance {
  55. NCDModuleInst *i;
  56. };
  57. struct use_instance {
  58. NCDModuleInst *i;
  59. struct instance *blocker;
  60. LinkedList2Node blocker_node;
  61. };
  62. static void func_new (NCDModuleInst *i)
  63. {
  64. // allocate instance
  65. struct instance *o = malloc(sizeof(*o));
  66. if (!o) {
  67. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  68. goto fail0;
  69. }
  70. NCDModuleInst_Backend_SetUser(i, o);
  71. // init arguments
  72. o->i = i;
  73. // check arguments
  74. if (!NCDValue_ListRead(o->i->args, 0)) {
  75. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  76. goto fail1;
  77. }
  78. // init users list
  79. LinkedList2_Init(&o->users);
  80. // set not up
  81. o->up = 0;
  82. // set not dying
  83. o->dying = 0;
  84. // signal up
  85. NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
  86. return;
  87. fail1:
  88. free(o);
  89. fail0:
  90. NCDModuleInst_Backend_SetError(i);
  91. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  92. }
  93. static void instance_free (struct instance *o)
  94. {
  95. ASSERT(LinkedList2_IsEmpty(&o->users))
  96. NCDModuleInst *i = o->i;
  97. // free instance
  98. free(o);
  99. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  100. }
  101. static void func_die (void *vo)
  102. {
  103. struct instance *o = vo;
  104. ASSERT(!o->dying)
  105. // if we have no users, die right away, else wait for users
  106. if (LinkedList2_IsEmpty(&o->users)) {
  107. instance_free(o);
  108. return;
  109. }
  110. // set dying
  111. o->dying = 1;
  112. }
  113. static void updown_func_new_templ (NCDModuleInst *i, int up)
  114. {
  115. // allocate instance
  116. struct updown_instance *o = malloc(sizeof(*o));
  117. if (!o) {
  118. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  119. goto fail0;
  120. }
  121. NCDModuleInst_Backend_SetUser(i, o);
  122. // init arguments
  123. o->i = i;
  124. // check arguments
  125. if (!NCDValue_ListRead(o->i->args, 0)) {
  126. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  127. goto fail1;
  128. }
  129. // signal up
  130. NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
  131. // get method object
  132. struct instance *mo = i->method_object->inst_user;
  133. if (mo->up != up) {
  134. // change up state
  135. mo->up = up;
  136. // signal users
  137. LinkedList2Iterator it;
  138. LinkedList2Iterator_InitForward(&it, &mo->users);
  139. LinkedList2Node *node;
  140. while (node = LinkedList2Iterator_Next(&it)) {
  141. struct use_instance *user = UPPER_OBJECT(node, struct use_instance, blocker_node);
  142. ASSERT(user->blocker == mo)
  143. NCDModuleInst_Backend_Event(user->i, up ? NCDMODULE_EVENT_UP : NCDMODULE_EVENT_DOWN);
  144. }
  145. }
  146. return;
  147. fail1:
  148. free(o);
  149. fail0:
  150. NCDModuleInst_Backend_SetError(i);
  151. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  152. }
  153. static void up_func_new (NCDModuleInst *i)
  154. {
  155. updown_func_new_templ(i, 1);
  156. }
  157. static void down_func_new (NCDModuleInst *i)
  158. {
  159. updown_func_new_templ(i, 0);
  160. }
  161. static void updown_func_die (void *vo)
  162. {
  163. struct updown_instance *o = vo;
  164. NCDModuleInst *i = o->i;
  165. // free instance
  166. free(o);
  167. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  168. }
  169. static void use_func_new (NCDModuleInst *i)
  170. {
  171. // allocate instance
  172. struct use_instance *o = malloc(sizeof(*o));
  173. if (!o) {
  174. ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
  175. goto fail0;
  176. }
  177. NCDModuleInst_Backend_SetUser(i, o);
  178. // init arguments
  179. o->i = i;
  180. // check arguments
  181. if (!NCDValue_ListRead(o->i->args, 0)) {
  182. ModuleLog(o->i, BLOG_ERROR, "wrong arity");
  183. goto fail1;
  184. }
  185. // set blocker
  186. o->blocker = i->method_object->inst_user;
  187. // add to blocker's list
  188. LinkedList2_Append(&o->blocker->users, &o->blocker_node);
  189. // signal up if needed
  190. if (o->blocker->up) {
  191. NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
  192. }
  193. return;
  194. fail1:
  195. free(o);
  196. fail0:
  197. NCDModuleInst_Backend_SetError(i);
  198. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  199. }
  200. static void use_func_die (void *vo)
  201. {
  202. struct use_instance *o = vo;
  203. NCDModuleInst *i = o->i;
  204. // remove from blocker's list
  205. LinkedList2_Remove(&o->blocker->users, &o->blocker_node);
  206. // make the blocker die if needed
  207. if (o->blocker->dying && LinkedList2_IsEmpty(&o->blocker->users)) {
  208. instance_free(o->blocker);
  209. }
  210. // free instance
  211. free(o);
  212. NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
  213. }
  214. static const struct NCDModule modules[] = {
  215. {
  216. .type = "blocker",
  217. .func_new = func_new,
  218. .func_die = func_die
  219. }, {
  220. .type = "blocker::up",
  221. .func_new = up_func_new,
  222. .func_die = updown_func_die,
  223. }, {
  224. .type = "blocker::down",
  225. .func_new = down_func_new,
  226. .func_die = updown_func_die,
  227. }, {
  228. .type = "blocker::use",
  229. .func_new = use_func_new,
  230. .func_die = use_func_die,
  231. }, {
  232. .type = NULL
  233. }
  234. };
  235. const struct NCDModuleGroup ncdmodule_blocker = {
  236. .modules = modules
  237. };