BUnixSignal.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /**
  2. * @file BUnixSignal.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <inttypes.h>
  30. #include <stdlib.h>
  31. #include <limits.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <string.h>
  35. #ifdef BADVPN_USE_SIGNALFD
  36. #include <sys/signalfd.h>
  37. #endif
  38. #include <misc/balloc.h>
  39. #include <misc/nonblocking.h>
  40. #include <base/BLog.h>
  41. #include <system/BUnixSignal.h>
  42. #include <generated/blog_channel_BUnixSignal.h>
  43. #define BUNIXSIGNAL_MAX_SIGNALS 64
  44. #ifdef BADVPN_USE_SIGNALFD
  45. static void signalfd_handler (BUnixSignal *o, int events)
  46. {
  47. DebugObject_Access(&o->d_obj);
  48. // read a signal
  49. struct signalfd_siginfo siginfo;
  50. int bytes = read(o->signalfd_fd, &siginfo, sizeof(siginfo));
  51. if (bytes < 0) {
  52. int error = errno;
  53. if (error == EAGAIN || error == EWOULDBLOCK) {
  54. return;
  55. }
  56. BLog(BLOG_ERROR, "read failed (%d)", error);
  57. return;
  58. }
  59. ASSERT_FORCE(bytes == sizeof(siginfo))
  60. // check signal
  61. if (siginfo.ssi_signo > INT_MAX) {
  62. BLog(BLOG_ERROR, "read returned out of int range signo (%"PRIu32")", siginfo.ssi_signo);
  63. return;
  64. }
  65. int signo = siginfo.ssi_signo;
  66. if (sigismember(&o->signals, signo) <= 0) {
  67. BLog(BLOG_ERROR, "read returned wrong signo (%d)", signo);
  68. return;
  69. }
  70. BLog(BLOG_DEBUG, "dispatching signal %d", signo);
  71. // call handler
  72. o->handler(o->user, signo);
  73. return;
  74. }
  75. #endif
  76. #ifdef BADVPN_USE_KEVENT
  77. static void kevent_handler (struct BUnixSignal_kevent_entry *entry, u_int fflags, intptr_t data)
  78. {
  79. BUnixSignal *o = entry->parent;
  80. DebugObject_Access(&o->d_obj);
  81. // call signal
  82. o->handler(o->user, entry->signo);
  83. return;
  84. }
  85. #endif
  86. #ifdef BADVPN_USE_SELFPIPE
  87. struct BUnixSignal_selfpipe_entry *bunixsignal_selfpipe_entries[BUNIXSIGNAL_MAX_SIGNALS];
  88. static void free_selfpipe_entry (struct BUnixSignal_selfpipe_entry *entry)
  89. {
  90. BUnixSignal *o = entry->parent;
  91. // uninstall signal handler
  92. struct sigaction act;
  93. memset(&act, 0, sizeof(act));
  94. act.sa_handler = SIG_DFL;
  95. sigemptyset(&act.sa_mask);
  96. ASSERT_FORCE(sigaction(entry->signo, &act, NULL) == 0)
  97. // free BFileDescriptor
  98. BReactor_RemoveFileDescriptor(o->reactor, &entry->pipe_read_bfd);
  99. // close pipe
  100. ASSERT_FORCE(close(entry->pipefds[0]) == 0)
  101. ASSERT_FORCE(close(entry->pipefds[1]) == 0)
  102. }
  103. static void pipe_read_fd_handler (struct BUnixSignal_selfpipe_entry *entry, int events)
  104. {
  105. BUnixSignal *o = entry->parent;
  106. DebugObject_Access(&o->d_obj);
  107. // read a byte
  108. uint8_t b;
  109. if (read(entry->pipefds[0], &b, sizeof(b)) < 0) {
  110. int error = errno;
  111. if (error == EAGAIN || error == EWOULDBLOCK) {
  112. return;
  113. }
  114. BLog(BLOG_ERROR, "read failed (%d)", error);
  115. return;
  116. }
  117. // call handler
  118. o->handler(o->user, entry->signo);
  119. return;
  120. }
  121. static void signal_handler (int signo)
  122. {
  123. ASSERT(signo >= 0)
  124. ASSERT(signo < BUNIXSIGNAL_MAX_SIGNALS)
  125. struct BUnixSignal_selfpipe_entry *entry = bunixsignal_selfpipe_entries[signo];
  126. uint8_t b = 0;
  127. write(entry->pipefds[1], &b, sizeof(b));
  128. }
  129. #endif
  130. int BUnixSignal_Init (BUnixSignal *o, BReactor *reactor, sigset_t signals, BUnixSignal_handler handler, void *user)
  131. {
  132. // init arguments
  133. o->reactor = reactor;
  134. o->signals = signals;
  135. o->handler = handler;
  136. o->user = user;
  137. #ifdef BADVPN_USE_SIGNALFD
  138. // init signalfd fd
  139. if ((o->signalfd_fd = signalfd(-1, &o->signals, 0)) < 0) {
  140. BLog(BLOG_ERROR, "signalfd failed");
  141. goto fail0;
  142. }
  143. // set non-blocking
  144. if (fcntl(o->signalfd_fd, F_SETFL, O_NONBLOCK) < 0) {
  145. BLog(BLOG_ERROR, "cannot set non-blocking");
  146. goto fail1;
  147. }
  148. // init signalfd BFileDescriptor
  149. BFileDescriptor_Init(&o->signalfd_bfd, o->signalfd_fd, (BFileDescriptor_handler)signalfd_handler, o);
  150. if (!BReactor_AddFileDescriptor(o->reactor, &o->signalfd_bfd)) {
  151. BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
  152. goto fail1;
  153. }
  154. BReactor_SetFileDescriptorEvents(o->reactor, &o->signalfd_bfd, BREACTOR_READ);
  155. // block signals
  156. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  157. BLog(BLOG_ERROR, "sigprocmask block failed");
  158. goto fail2;
  159. }
  160. #endif
  161. #ifdef BADVPN_USE_KEVENT
  162. // count signals
  163. int num_signals = 0;
  164. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  165. if (!sigismember(&o->signals, i)) {
  166. continue;
  167. }
  168. num_signals++;
  169. }
  170. // allocate array
  171. if (!(o->entries = BAllocArray(num_signals, sizeof(o->entries[0])))) {
  172. BLog(BLOG_ERROR, "BAllocArray failed");
  173. goto fail0;
  174. }
  175. // init kevents
  176. o->num_entries = 0;
  177. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  178. if (!sigismember(&o->signals, i)) {
  179. continue;
  180. }
  181. struct BUnixSignal_kevent_entry *entry = &o->entries[o->num_entries];
  182. entry->parent = o;
  183. entry->signo = i;
  184. if (!BReactorKEvent_Init(&entry->kevent, o->reactor, (BReactorKEvent_handler)kevent_handler, entry, entry->signo, EVFILT_SIGNAL, 0, 0)) {
  185. BLog(BLOG_ERROR, "BReactorKEvent_Init failed");
  186. goto fail2;
  187. }
  188. o->num_entries++;
  189. }
  190. // block signals
  191. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  192. BLog(BLOG_ERROR, "sigprocmask block failed");
  193. goto fail2;
  194. }
  195. #endif
  196. #ifdef BADVPN_USE_SELFPIPE
  197. // count signals
  198. int num_signals = 0;
  199. for (int i = 1; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  200. if (!sigismember(&o->signals, i)) {
  201. continue;
  202. }
  203. num_signals++;
  204. }
  205. // allocate array
  206. if (!(o->entries = BAllocArray(num_signals, sizeof(o->entries[0])))) {
  207. BLog(BLOG_ERROR, "BAllocArray failed");
  208. goto fail0;
  209. }
  210. // init entries
  211. o->num_entries = 0;
  212. for (int i = 1; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  213. if (!sigismember(&o->signals, i)) {
  214. continue;
  215. }
  216. struct BUnixSignal_selfpipe_entry *entry = &o->entries[o->num_entries];
  217. entry->parent = o;
  218. entry->signo = i;
  219. // init pipe
  220. if (pipe(entry->pipefds) < 0) {
  221. BLog(BLOG_ERROR, "pipe failed");
  222. goto loop_fail0;
  223. }
  224. // set pipe ends non-blocking
  225. if (!badvpn_set_nonblocking(entry->pipefds[0]) || !badvpn_set_nonblocking(entry->pipefds[1])) {
  226. BLog(BLOG_ERROR, "set nonblocking failed");
  227. goto loop_fail1;
  228. }
  229. // init read end BFileDescriptor
  230. BFileDescriptor_Init(&entry->pipe_read_bfd, entry->pipefds[0], (BFileDescriptor_handler)pipe_read_fd_handler, entry);
  231. if (!BReactor_AddFileDescriptor(o->reactor, &entry->pipe_read_bfd)) {
  232. BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
  233. goto loop_fail1;
  234. }
  235. BReactor_SetFileDescriptorEvents(o->reactor, &entry->pipe_read_bfd, BREACTOR_READ);
  236. // set global entry pointer
  237. bunixsignal_selfpipe_entries[entry->signo] = entry;
  238. // install signal handler
  239. struct sigaction act;
  240. memset(&act, 0, sizeof(act));
  241. act.sa_handler = signal_handler;
  242. sigemptyset(&act.sa_mask);
  243. if (sigaction(entry->signo, &act, NULL) < 0) {
  244. BLog(BLOG_ERROR, "sigaction failed");
  245. goto loop_fail2;
  246. }
  247. o->num_entries++;
  248. continue;
  249. loop_fail2:
  250. BReactor_RemoveFileDescriptor(o->reactor, &entry->pipe_read_bfd);
  251. loop_fail1:
  252. ASSERT_FORCE(close(entry->pipefds[0]) == 0)
  253. ASSERT_FORCE(close(entry->pipefds[1]) == 0)
  254. loop_fail0:
  255. goto fail2;
  256. }
  257. #endif
  258. DebugObject_Init(&o->d_obj);
  259. return 1;
  260. #ifdef BADVPN_USE_SIGNALFD
  261. fail2:
  262. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  263. fail1:
  264. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  265. #endif
  266. #ifdef BADVPN_USE_KEVENT
  267. fail2:
  268. while (o->num_entries > 0) {
  269. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  270. o->num_entries--;
  271. }
  272. BFree(o->entries);
  273. #endif
  274. #ifdef BADVPN_USE_SELFPIPE
  275. fail2:
  276. while (o->num_entries > 0) {
  277. free_selfpipe_entry(&o->entries[o->num_entries - 1]);
  278. o->num_entries--;
  279. }
  280. BFree(o->entries);
  281. #endif
  282. fail0:
  283. return 0;
  284. }
  285. void BUnixSignal_Free (BUnixSignal *o, int unblock)
  286. {
  287. ASSERT(unblock == 0 || unblock == 1)
  288. DebugObject_Free(&o->d_obj);
  289. #ifdef BADVPN_USE_SIGNALFD
  290. if (unblock) {
  291. // unblock signals
  292. ASSERT_FORCE(sigprocmask(SIG_UNBLOCK, &o->signals, 0) == 0)
  293. }
  294. // free signalfd BFileDescriptor
  295. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  296. // free signalfd fd
  297. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  298. #endif
  299. #ifdef BADVPN_USE_KEVENT
  300. if (unblock) {
  301. // unblock signals
  302. ASSERT_FORCE(sigprocmask(SIG_UNBLOCK, &o->signals, 0) == 0)
  303. }
  304. // free kevents
  305. while (o->num_entries > 0) {
  306. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  307. o->num_entries--;
  308. }
  309. // free array
  310. BFree(o->entries);
  311. #endif
  312. #ifdef BADVPN_USE_SELFPIPE
  313. if (!unblock) {
  314. // block signals
  315. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  316. BLog(BLOG_ERROR, "sigprocmask block failed");
  317. }
  318. }
  319. // free entries
  320. while (o->num_entries > 0) {
  321. free_selfpipe_entry(&o->entries[o->num_entries - 1]);
  322. o->num_entries--;
  323. }
  324. // free array
  325. BFree(o->entries);
  326. #endif
  327. }