BPRFileDesc.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 dispatch_event (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. // schedule job that will call further handlers, or update bottom events at the end
  67. BPending_Set(&o->job);
  68. do {
  69. // get event
  70. int ev_index = o->current_event_index;
  71. PRInt16 ev_mask = handler_events[ev_index];
  72. int ev_dispatch = (o->ready_events&ev_mask);
  73. // jump to next event, clear this event
  74. o->current_event_index++;
  75. o->ready_events &= ~ev_mask;
  76. if (ev_dispatch) {
  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. } while (o->current_event_index < NUM_EVENTS);
  84. ASSERT(!o->ready_events)
  85. }
  86. void job_handler (BPRFileDesc *o)
  87. {
  88. ASSERT(o->dispatching)
  89. ASSERT(o->current_event_index >= 0)
  90. ASSERT(o->current_event_index <= NUM_EVENTS)
  91. ASSERT(((o->ready_events)&~(o->waitEvents)) == 0) // BPRFileDesc_DisableEvent clears events from ready_events
  92. DebugObject_Access(&o->d_obj);
  93. if (o->ready_events) {
  94. dispatch_event(o);
  95. return;
  96. }
  97. o->dispatching = 0;
  98. // recalculate bottom events
  99. update_bottom(o);
  100. }
  101. void dispatch_events (BPRFileDesc *o, PRInt16 events)
  102. {
  103. ASSERT(!o->dispatching)
  104. ASSERT((events&~(o->waitEvents)) == 0)
  105. o->dispatching = 1;
  106. o->ready_events = events;
  107. o->current_event_index = 0;
  108. dispatch_event(o);
  109. return;
  110. }
  111. int get_bsocket_events (PRUint16 pr_events)
  112. {
  113. int res = 0;
  114. if (pr_events&PR_POLL_READ) {
  115. res |= BSOCKET_READ;
  116. }
  117. if (pr_events&PR_POLL_WRITE) {
  118. res |= BSOCKET_WRITE;
  119. }
  120. return res;
  121. }
  122. void init_bottom (BPRFileDesc *obj)
  123. {
  124. PRFileDesc *layer = obj->prfd;
  125. do {
  126. if (layer->identity == bsocketprfiledesc_identity) {
  127. obj->bottom_type = BPRFILEDESC_BOTTOM_BSOCKET;
  128. obj->bottom = layer;
  129. BSocket_AddGlobalEventHandler((BSocket *)obj->bottom->secret, (BSocket_handler)socket_handler, obj);
  130. return;
  131. }
  132. layer = layer->lower;
  133. } while (layer);
  134. ASSERT(0)
  135. }
  136. void free_bottom (BPRFileDesc *obj)
  137. {
  138. switch (obj->bottom_type) {
  139. case BPRFILEDESC_BOTTOM_BSOCKET:
  140. BSocket_RemoveGlobalEventHandler((BSocket *)obj->bottom->secret);
  141. break;
  142. default:
  143. ASSERT(0)
  144. break;
  145. }
  146. }
  147. void update_bottom (BPRFileDesc *obj)
  148. {
  149. // calculate bottom events
  150. PRInt16 new_bottom_events = 0;
  151. PRInt16 new_flags;
  152. PRInt16 out_flags;
  153. if (obj->waitEvents&PR_POLL_READ) {
  154. new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_READ, &out_flags);
  155. if ((new_flags&out_flags) == 0) {
  156. new_bottom_events |= new_flags;
  157. }
  158. }
  159. if (obj->waitEvents&PR_POLL_WRITE) {
  160. new_flags = obj->prfd->methods->poll(obj->prfd, PR_POLL_WRITE, &out_flags);
  161. if ((new_flags&out_flags) == 0) {
  162. new_bottom_events |= new_flags;
  163. }
  164. }
  165. switch (obj->bottom_type) {
  166. case BPRFILEDESC_BOTTOM_BSOCKET:
  167. BSocket_SetGlobalEvents((BSocket *)obj->bottom->secret, get_bsocket_events(new_bottom_events));
  168. break;
  169. default:
  170. ASSERT(0)
  171. break;
  172. }
  173. }
  174. void socket_handler (BPRFileDesc *obj, int events)
  175. {
  176. ASSERT(!obj->dispatching)
  177. // dispatch all events the user is waiting for, as there is
  178. // no way to know which of those are ready
  179. dispatch_events(obj, obj->waitEvents);
  180. return;
  181. }
  182. void BPRFileDesc_Init (BPRFileDesc *obj, PRFileDesc *prfd)
  183. {
  184. obj->prfd = prfd;
  185. init_handlers(obj);
  186. obj->waitEvents = 0;
  187. obj->dispatching = 0;
  188. obj->ready_events = 0; // just initialize it so we can clear them safely from BPRFileDesc_DisableEvent
  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. // init debug object
  193. DebugObject_Init(&obj->d_obj);
  194. }
  195. void BPRFileDesc_Free (BPRFileDesc *obj)
  196. {
  197. // free debug object
  198. DebugObject_Free(&obj->d_obj);
  199. // free job
  200. BPending_Free(&obj->job);
  201. free_bottom(obj);
  202. }
  203. void BPRFileDesc_AddEventHandler (BPRFileDesc *obj, PRInt16 event, BPRFileDesc_handler handler, void *user)
  204. {
  205. ASSERT(handler)
  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. // get index
  217. int index = get_event_index(event);
  218. // event must have handler
  219. ASSERT(obj->handlers[index])
  220. // disable event if enabled
  221. if (obj->waitEvents&event) {
  222. BPRFileDesc_DisableEvent(obj, event);
  223. }
  224. // change handler
  225. obj->handlers[index] = NULL;
  226. }
  227. void BPRFileDesc_EnableEvent (BPRFileDesc *obj, PRInt16 event)
  228. {
  229. // get index
  230. int index = get_event_index(event);
  231. // event must have handler
  232. ASSERT(obj->handlers[index])
  233. // event must not be enabled
  234. ASSERT(!(obj->waitEvents&event))
  235. // update events
  236. obj->waitEvents |= event;
  237. // update bottom
  238. if (!obj->dispatching) {
  239. update_bottom(obj);
  240. }
  241. }
  242. void BPRFileDesc_DisableEvent (BPRFileDesc *obj, PRInt16 event)
  243. {
  244. // get index
  245. int index = get_event_index(event);
  246. // event must have handler
  247. ASSERT(obj->handlers[index])
  248. // event must be enabled
  249. ASSERT(obj->waitEvents&event)
  250. // update events
  251. obj->waitEvents &= ~event;
  252. obj->ready_events &= ~event;
  253. // update bottom
  254. if (!obj->dispatching) {
  255. update_bottom(obj);
  256. }
  257. }