BUnixSignal.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /**
  2. * @file BUnixSignal.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 <inttypes.h>
  23. #include <stdlib.h>
  24. #include <limits.h>
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #ifdef BADVPN_USE_SIGNALFD
  28. #include <sys/signalfd.h>
  29. #endif
  30. #include <misc/balloc.h>
  31. #include <system/BLog.h>
  32. #include <system/BUnixSignal.h>
  33. #include <generated/blog_channel_BUnixSignal.h>
  34. #define BUNIXSIGNAL_MAX_SIGNALS 64
  35. #ifdef BADVPN_USE_SIGNALFD
  36. static void signalfd_handler (BUnixSignal *o, int events)
  37. {
  38. DebugObject_Access(&o->d_obj);
  39. // read a signal
  40. struct signalfd_siginfo siginfo;
  41. int bytes = read(o->signalfd_fd, &siginfo, sizeof(siginfo));
  42. if (bytes < 0) {
  43. int error = errno;
  44. if (error == EAGAIN || error == EWOULDBLOCK) {
  45. return;
  46. }
  47. BLog(BLOG_ERROR, "read failed (%d)", error);
  48. return;
  49. }
  50. ASSERT_FORCE(bytes == sizeof(siginfo))
  51. // check signal
  52. if (siginfo.ssi_signo > INT_MAX) {
  53. BLog(BLOG_ERROR, "read returned out of int range signo (%"PRIu32")", siginfo.ssi_signo);
  54. return;
  55. }
  56. int signo = siginfo.ssi_signo;
  57. if (sigismember(&o->signals, signo) <= 0) {
  58. BLog(BLOG_ERROR, "read returned wrong signo (%d)", signo);
  59. return;
  60. }
  61. BLog(BLOG_DEBUG, "dispatching signal %d", signo);
  62. // call handler
  63. o->handler(o->user, signo);
  64. return;
  65. }
  66. #endif
  67. #ifdef BADVPN_USE_KEVENT
  68. static void kevent_handler (struct BUnixSignal_kevent_entry *entry, u_int fflags, intptr_t data)
  69. {
  70. BUnixSignal *o = entry->parent;
  71. DebugObject_Access(&o->d_obj);
  72. // call signal
  73. o->handler(o->user, entry->signo);
  74. return;
  75. }
  76. #endif
  77. int BUnixSignal_Init (BUnixSignal *o, BReactor *reactor, sigset_t signals, BUnixSignal_handler handler, void *user)
  78. {
  79. // init arguments
  80. o->reactor = reactor;
  81. o->signals = signals;
  82. o->handler = handler;
  83. o->user = user;
  84. #ifdef BADVPN_USE_SIGNALFD
  85. // init signalfd fd
  86. if ((o->signalfd_fd = signalfd(-1, &o->signals, 0)) < 0) {
  87. BLog(BLOG_ERROR, "signalfd failed");
  88. goto fail0;
  89. }
  90. // set non-blocking
  91. if (fcntl(o->signalfd_fd, F_SETFL, O_NONBLOCK) < 0) {
  92. DEBUG("cannot set non-blocking");
  93. goto fail1;
  94. }
  95. // init signalfd BFileDescriptor
  96. BFileDescriptor_Init(&o->signalfd_bfd, o->signalfd_fd, (BFileDescriptor_handler)signalfd_handler, o);
  97. if (!BReactor_AddFileDescriptor(o->reactor, &o->signalfd_bfd)) {
  98. BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
  99. goto fail1;
  100. }
  101. BReactor_SetFileDescriptorEvents(o->reactor, &o->signalfd_bfd, BREACTOR_READ);
  102. #endif
  103. #ifdef BADVPN_USE_KEVENT
  104. // count signals
  105. int num_signals = 0;
  106. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  107. if (!sigismember(&o->signals, i)) {
  108. continue;
  109. }
  110. num_signals++;
  111. }
  112. // allocate array
  113. if (!(o->entries = BAllocArray(num_signals, sizeof(o->entries[0])))) {
  114. BLog(BLOG_ERROR, "BAllocArray failed");
  115. goto fail0;
  116. }
  117. // init kevents
  118. o->num_entries = 0;
  119. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  120. if (!sigismember(&o->signals, i)) {
  121. continue;
  122. }
  123. struct BUnixSignal_kevent_entry *entry = &o->entries[o->num_entries];
  124. entry->parent = o;
  125. entry->signo = i;
  126. if (!BReactorKEvent_Init(&entry->kevent, o->reactor, (BReactorKEvent_handler)kevent_handler, entry, entry->signo, EVFILT_SIGNAL, 0, 0)) {
  127. BLog(BLOG_ERROR, "BReactorKEvent_Init failed");
  128. goto fail2;
  129. }
  130. o->num_entries++;
  131. }
  132. #endif
  133. // block signals
  134. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  135. BLog(BLOG_ERROR, "sigprocmask block failed");
  136. goto fail2;
  137. }
  138. DebugObject_Init(&o->d_obj);
  139. return 1;
  140. #ifdef BADVPN_USE_SIGNALFD
  141. fail2:
  142. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  143. fail1:
  144. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  145. #endif
  146. #ifdef BADVPN_USE_KEVENT
  147. fail2:
  148. while (o->num_entries > 0) {
  149. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  150. o->num_entries--;
  151. }
  152. BFree(o->entries);
  153. #endif
  154. fail0:
  155. return 0;
  156. }
  157. void BUnixSignal_Free (BUnixSignal *o, int unblock)
  158. {
  159. ASSERT(unblock == 0 || unblock == 1)
  160. DebugObject_Free(&o->d_obj);
  161. if (unblock) {
  162. // unblock signals
  163. ASSERT_FORCE(sigprocmask(SIG_UNBLOCK, &o->signals, 0) == 0)
  164. }
  165. #ifdef BADVPN_USE_SIGNALFD
  166. // free signalfd BFileDescriptor
  167. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  168. // free signalfd fd
  169. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  170. #endif
  171. #ifdef BADVPN_USE_KEVENT
  172. // free kevents
  173. while (o->num_entries > 0) {
  174. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  175. o->num_entries--;
  176. }
  177. // free array
  178. BFree(o->entries);
  179. #endif
  180. }