BPRFileDesc.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /**
  2. * @file BPRFileDesc.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 <stdlib.h>
  23. #include <misc/offset.h>
  24. #include <misc/debug.h>
  25. #include <nspr_support/BPRFileDesc.h>
  26. #define HANDLER_READ 0
  27. #define HANDLER_WRITE 1
  28. #define NUM_EVENTS 2
  29. static int get_event_index (PRInt16 event);
  30. static void init_handlers (BPRFileDesc *obj);
  31. static int get_bsocket_events (PRUint16 pr_events);
  32. static void init_bottom (BPRFileDesc *obj);
  33. static void free_bottom (BPRFileDesc *obj);
  34. static void update_bottom (BPRFileDesc *obj);
  35. static void set_bottom_events (BPRFileDesc *obj, PRInt16 new_events);
  36. static void socket_handler (BPRFileDesc *obj, int event);
  37. int get_event_index (PRInt16 event)
  38. {
  39. switch (event) {
  40. case PR_POLL_READ:
  41. return HANDLER_READ;
  42. case PR_POLL_WRITE:
  43. return HANDLER_WRITE;
  44. default:
  45. ASSERT(0)
  46. return 0;
  47. }
  48. }
  49. static PRInt16 handler_events[] = {
  50. [HANDLER_READ] = PR_POLL_READ,
  51. [HANDLER_WRITE] = PR_POLL_WRITE
  52. };
  53. void init_handlers (BPRFileDesc *obj)
  54. {
  55. int i;
  56. for (i = 0; i < NUM_EVENTS; i++) {
  57. obj->handlers[i] = NULL;
  58. }
  59. }
  60. void work_events (BPRFileDesc *o)
  61. {
  62. ASSERT(o->dispatching)
  63. ASSERT(o->current_event_index >= 0)
  64. ASSERT(o->current_event_index <= NUM_EVENTS)
  65. ASSERT(((o->ready_events)&~(o->waitEvents)) == 0)
  66. while (o->current_event_index < NUM_EVENTS) {
  67. // get event
  68. int ev_index = o->current_event_index;
  69. PRInt16 ev_mask = handler_events[ev_index];
  70. int ev_dispatch = (o->ready_events&ev_mask);
  71. // jump to next event, clear this event
  72. o->current_event_index++;
  73. o->ready_events &= ~ev_mask;
  74. if (ev_dispatch) {
  75. // schedule job that will call further handlers, or update bottom events at the end
  76. BPending_Set(&o->job);
  77. // disable event before dispatching it
  78. BPRFileDesc_DisableEvent(o, ev_mask);
  79. // dispatch this event
  80. o->handlers[ev_index](o->handlers_user[ev_index], ev_mask);
  81. return;
  82. }
  83. }
  84. ASSERT(!o->ready_events)
  85. o->dispatching = 0;
  86. // recalculate bottom events
  87. update_bottom(o);
  88. }
  89. void job_handler (BPRFileDesc *o)
  90. {
  91. ASSERT(o->dispatching)
  92. ASSERT(o->current_event_index >= 0)
  93. ASSERT(o->current_event_index <= NUM_EVENTS)
  94. ASSERT(((o->ready_events)&~(o->waitEvents)) == 0) // BPRFileDesc_DisableEvent clears events from ready_events
  95. DebugObject_Access(&o->d_obj);
  96. work_events(o);
  97. return;
  98. }
  99. void dispatch_events (BPRFileDesc *o, PRInt16 events)
  100. {
  101. ASSERT(!o->dispatching)
  102. ASSERT((events&~(o->waitEvents)) == 0)
  103. o->dispatching = 1;
  104. o->ready_events = events;
  105. o->current_event_index = 0;
  106. work_events(o);
  107. return;
  108. }
  109. int get_bsocket_events (PRUint16 pr_events)
  110. {
  111. int res = 0;
  112. if (pr_events&PR_POLL_READ) {
  113. res |= BSOCKET_READ;
  114. }
  115. if (pr_events&PR_POLL_WRITE) {
  116. res |= BSOCKET_WRITE;
  117. }
  118. return res;
  119. }
  120. void init_bottom (BPRFileDesc *obj)
  121. {
  122. PRFileDesc *layer = obj->prfd;
  123. do {
  124. if (layer->identity == bsocketprfiledesc_identity) {
  125. obj->bottom_type = BPRFILEDESC_BOTTOM_BSOCKET;
  126. obj->bottom = layer;
  127. BSocket_AddGlobalEventHandler((BSocket *)obj->bottom->secret, (BSocket_handler)socket_handler, obj);
  128. return;
  129. }
  130. layer = layer->lower;
  131. } while (layer);
  132. ASSERT(0)
  133. }
  134. void free_bottom (BPRFileDesc *obj)
  135. {
  136. switch (obj->bottom_type) {
  137. case BPRFILEDESC_BOTTOM_BSOCKET:
  138. BSocket_RemoveGlobalEventHandler((BSocket *)obj->bottom->secret);
  139. break;
  140. default:
  141. ASSERT(0)
  142. break;
  143. }
  144. }
  145. void update_bottom (BPRFileDesc *obj)
  146. {
  147. // calculate bottom events
  148. PRInt16 new_bottom_events = 0;
  149. PRInt16 new_flags;
  150. PRInt16 out_flags;
  151. if (obj->waitEvents&PR_POLL_READ) {
  152. new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_READ, &out_flags);
  153. if ((new_flags&out_flags) == 0) {
  154. new_bottom_events |= new_flags;
  155. }
  156. }
  157. if (obj->waitEvents&PR_POLL_WRITE) {
  158. new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_WRITE, &out_flags);
  159. if ((new_flags&out_flags) == 0) {
  160. new_bottom_events |= new_flags;
  161. }
  162. }
  163. switch (obj->bottom_type) {
  164. case BPRFILEDESC_BOTTOM_BSOCKET:
  165. BSocket_SetGlobalEvents((BSocket *)obj->bottom->secret, get_bsocket_events(new_bottom_events));
  166. break;
  167. default:
  168. ASSERT(0)
  169. break;
  170. }
  171. }
  172. void socket_handler (BPRFileDesc *obj, int events)
  173. {
  174. ASSERT(!obj->dispatching)
  175. DebugObject_Access(&obj->d_obj);
  176. // dispatch all events the user is waiting for, as there is
  177. // no way to know which of those are ready
  178. dispatch_events(obj, obj->waitEvents);
  179. return;
  180. }
  181. void BPRFileDesc_Init (BPRFileDesc *obj, PRFileDesc *prfd)
  182. {
  183. obj->prfd = prfd;
  184. init_handlers(obj);
  185. obj->waitEvents = 0;
  186. obj->dispatching = 0;
  187. obj->ready_events = 0; // just initialize it so we can clear them safely from BPRFileDesc_DisableEvent
  188. // init bottom
  189. init_bottom(obj);
  190. // init job
  191. BPending_Init(&obj->job, BReactor_PendingGroup(((BSocket *)obj->bottom->secret)->bsys), (BPending_handler)job_handler, obj);
  192. DebugObject_Init(&obj->d_obj);
  193. }
  194. void BPRFileDesc_Free (BPRFileDesc *obj)
  195. {
  196. DebugObject_Free(&obj->d_obj);
  197. // free job
  198. BPending_Free(&obj->job);
  199. // free bottom
  200. free_bottom(obj);
  201. }
  202. void BPRFileDesc_AddEventHandler (BPRFileDesc *obj, PRInt16 event, BPRFileDesc_handler handler, void *user)
  203. {
  204. ASSERT(handler)
  205. DebugObject_Access(&obj->d_obj);
  206. // get index
  207. int index = get_event_index(event);
  208. // event must not have handler
  209. ASSERT(!obj->handlers[index])
  210. // change handler
  211. obj->handlers[index] = handler;
  212. obj->handlers_user[index] = user;
  213. }
  214. void BPRFileDesc_RemoveEventHandler (BPRFileDesc *obj, PRInt16 event)
  215. {
  216. DebugObject_Access(&obj->d_obj);
  217. // get index
  218. int index = get_event_index(event);
  219. // event must have handler
  220. ASSERT(obj->handlers[index])
  221. // disable event if enabled
  222. if (obj->waitEvents&event) {
  223. BPRFileDesc_DisableEvent(obj, event);
  224. }
  225. // change handler
  226. obj->handlers[index] = NULL;
  227. }
  228. void BPRFileDesc_EnableEvent (BPRFileDesc *obj, PRInt16 event)
  229. {
  230. DebugObject_Access(&obj->d_obj);
  231. // get index
  232. int index = get_event_index(event);
  233. // event must have handler
  234. ASSERT(obj->handlers[index])
  235. // event must not be enabled
  236. ASSERT(!(obj->waitEvents&event))
  237. // update events
  238. obj->waitEvents |= event;
  239. // update bottom
  240. if (!obj->dispatching) {
  241. update_bottom(obj);
  242. }
  243. }
  244. void BPRFileDesc_DisableEvent (BPRFileDesc *obj, PRInt16 event)
  245. {
  246. DebugObject_Access(&obj->d_obj);
  247. // get index
  248. int index = get_event_index(event);
  249. // event must have handler
  250. ASSERT(obj->handlers[index])
  251. // event must be enabled
  252. ASSERT(obj->waitEvents&event)
  253. // update events
  254. obj->waitEvents &= ~event;
  255. obj->ready_events &= ~event;
  256. // update bottom
  257. if (!obj->dispatching) {
  258. update_bottom(obj);
  259. }
  260. }