BUnixSignal.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. #include <string.h>
  28. #ifdef BADVPN_USE_SIGNALFD
  29. #include <sys/signalfd.h>
  30. #endif
  31. #include <misc/balloc.h>
  32. #include <misc/nonblocking.h>
  33. #include <system/BLog.h>
  34. #include <system/BUnixSignal.h>
  35. #include <generated/blog_channel_BUnixSignal.h>
  36. #define BUNIXSIGNAL_MAX_SIGNALS 64
  37. #ifdef BADVPN_USE_SIGNALFD
  38. static void signalfd_handler (BUnixSignal *o, int events)
  39. {
  40. DebugObject_Access(&o->d_obj);
  41. // read a signal
  42. struct signalfd_siginfo siginfo;
  43. int bytes = read(o->signalfd_fd, &siginfo, sizeof(siginfo));
  44. if (bytes < 0) {
  45. int error = errno;
  46. if (error == EAGAIN || error == EWOULDBLOCK) {
  47. return;
  48. }
  49. BLog(BLOG_ERROR, "read failed (%d)", error);
  50. return;
  51. }
  52. ASSERT_FORCE(bytes == sizeof(siginfo))
  53. // check signal
  54. if (siginfo.ssi_signo > INT_MAX) {
  55. BLog(BLOG_ERROR, "read returned out of int range signo (%"PRIu32")", siginfo.ssi_signo);
  56. return;
  57. }
  58. int signo = siginfo.ssi_signo;
  59. if (sigismember(&o->signals, signo) <= 0) {
  60. BLog(BLOG_ERROR, "read returned wrong signo (%d)", signo);
  61. return;
  62. }
  63. BLog(BLOG_DEBUG, "dispatching signal %d", signo);
  64. // call handler
  65. o->handler(o->user, signo);
  66. return;
  67. }
  68. #endif
  69. #ifdef BADVPN_USE_KEVENT
  70. static void kevent_handler (struct BUnixSignal_kevent_entry *entry, u_int fflags, intptr_t data)
  71. {
  72. BUnixSignal *o = entry->parent;
  73. DebugObject_Access(&o->d_obj);
  74. // call signal
  75. o->handler(o->user, entry->signo);
  76. return;
  77. }
  78. #endif
  79. #ifdef BADVPN_USE_SELFPIPE
  80. struct BUnixSignal_selfpipe_entry *bunixsignal_selfpipe_entries[BUNIXSIGNAL_MAX_SIGNALS];
  81. static void free_selfpipe_entry (struct BUnixSignal_selfpipe_entry *entry)
  82. {
  83. BUnixSignal *o = entry->parent;
  84. // uninstall signal handler
  85. struct sigaction act;
  86. memset(&act, 0, sizeof(act));
  87. act.sa_handler = SIG_DFL;
  88. sigemptyset(&act.sa_mask);
  89. ASSERT_FORCE(sigaction(entry->signo, &act, NULL) == 0)
  90. // free BFileDescriptor
  91. BReactor_RemoveFileDescriptor(o->reactor, &entry->pipe_read_bfd);
  92. // close pipe
  93. ASSERT_FORCE(close(entry->pipefds[0]) == 0)
  94. ASSERT_FORCE(close(entry->pipefds[1]) == 0)
  95. }
  96. static void pipe_read_fd_handler (struct BUnixSignal_selfpipe_entry *entry, int events)
  97. {
  98. BUnixSignal *o = entry->parent;
  99. DebugObject_Access(&o->d_obj);
  100. // read a byte
  101. uint8_t b;
  102. if (read(entry->pipefds[0], &b, sizeof(b)) < 0) {
  103. int error = errno;
  104. if (error == EAGAIN || error == EWOULDBLOCK) {
  105. return;
  106. }
  107. BLog(BLOG_ERROR, "read failed (%d)", error);
  108. return;
  109. }
  110. // call handler
  111. o->handler(o->user, entry->signo);
  112. return;
  113. }
  114. static void signal_handler (int signo)
  115. {
  116. ASSERT(signo >= 0)
  117. ASSERT(signo < BUNIXSIGNAL_MAX_SIGNALS)
  118. struct BUnixSignal_selfpipe_entry *entry = bunixsignal_selfpipe_entries[signo];
  119. uint8_t b = 0;
  120. write(entry->pipefds[1], &b, sizeof(b));
  121. }
  122. #endif
  123. int BUnixSignal_Init (BUnixSignal *o, BReactor *reactor, sigset_t signals, BUnixSignal_handler handler, void *user)
  124. {
  125. // init arguments
  126. o->reactor = reactor;
  127. o->signals = signals;
  128. o->handler = handler;
  129. o->user = user;
  130. #ifdef BADVPN_USE_SIGNALFD
  131. // init signalfd fd
  132. if ((o->signalfd_fd = signalfd(-1, &o->signals, 0)) < 0) {
  133. BLog(BLOG_ERROR, "signalfd failed");
  134. goto fail0;
  135. }
  136. // set non-blocking
  137. if (fcntl(o->signalfd_fd, F_SETFL, O_NONBLOCK) < 0) {
  138. BLog(BLOG_ERROR, "cannot set non-blocking");
  139. goto fail1;
  140. }
  141. // init signalfd BFileDescriptor
  142. BFileDescriptor_Init(&o->signalfd_bfd, o->signalfd_fd, (BFileDescriptor_handler)signalfd_handler, o);
  143. if (!BReactor_AddFileDescriptor(o->reactor, &o->signalfd_bfd)) {
  144. BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
  145. goto fail1;
  146. }
  147. BReactor_SetFileDescriptorEvents(o->reactor, &o->signalfd_bfd, BREACTOR_READ);
  148. // block signals
  149. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  150. BLog(BLOG_ERROR, "sigprocmask block failed");
  151. goto fail2;
  152. }
  153. #endif
  154. #ifdef BADVPN_USE_KEVENT
  155. // count signals
  156. int num_signals = 0;
  157. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  158. if (!sigismember(&o->signals, i)) {
  159. continue;
  160. }
  161. num_signals++;
  162. }
  163. // allocate array
  164. if (!(o->entries = BAllocArray(num_signals, sizeof(o->entries[0])))) {
  165. BLog(BLOG_ERROR, "BAllocArray failed");
  166. goto fail0;
  167. }
  168. // init kevents
  169. o->num_entries = 0;
  170. for (int i = 0; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  171. if (!sigismember(&o->signals, i)) {
  172. continue;
  173. }
  174. struct BUnixSignal_kevent_entry *entry = &o->entries[o->num_entries];
  175. entry->parent = o;
  176. entry->signo = i;
  177. if (!BReactorKEvent_Init(&entry->kevent, o->reactor, (BReactorKEvent_handler)kevent_handler, entry, entry->signo, EVFILT_SIGNAL, 0, 0)) {
  178. BLog(BLOG_ERROR, "BReactorKEvent_Init failed");
  179. goto fail2;
  180. }
  181. o->num_entries++;
  182. }
  183. // block signals
  184. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  185. BLog(BLOG_ERROR, "sigprocmask block failed");
  186. goto fail2;
  187. }
  188. #endif
  189. #ifdef BADVPN_USE_SELFPIPE
  190. // count signals
  191. int num_signals = 0;
  192. for (int i = 1; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  193. if (!sigismember(&o->signals, i)) {
  194. continue;
  195. }
  196. num_signals++;
  197. }
  198. // allocate array
  199. if (!(o->entries = BAllocArray(num_signals, sizeof(o->entries[0])))) {
  200. BLog(BLOG_ERROR, "BAllocArray failed");
  201. goto fail0;
  202. }
  203. // init entries
  204. o->num_entries = 0;
  205. for (int i = 1; i < BUNIXSIGNAL_MAX_SIGNALS; i++) {
  206. if (!sigismember(&o->signals, i)) {
  207. continue;
  208. }
  209. struct BUnixSignal_selfpipe_entry *entry = &o->entries[o->num_entries];
  210. entry->parent = o;
  211. entry->signo = i;
  212. // init pipe
  213. if (pipe(entry->pipefds) < 0) {
  214. BLog(BLOG_ERROR, "pipe failed");
  215. goto loop_fail0;
  216. }
  217. // set pipe ends non-blocking
  218. if (!badvpn_set_nonblocking(entry->pipefds[0]) || !badvpn_set_nonblocking(entry->pipefds[1])) {
  219. BLog(BLOG_ERROR, "set nonblocking failed");
  220. goto loop_fail1;
  221. }
  222. // init read end BFileDescriptor
  223. BFileDescriptor_Init(&entry->pipe_read_bfd, entry->pipefds[0], (BFileDescriptor_handler)pipe_read_fd_handler, entry);
  224. if (!BReactor_AddFileDescriptor(o->reactor, &entry->pipe_read_bfd)) {
  225. BLog(BLOG_ERROR, "BReactor_AddFileDescriptor failed");
  226. goto loop_fail1;
  227. }
  228. BReactor_SetFileDescriptorEvents(o->reactor, &entry->pipe_read_bfd, BREACTOR_READ);
  229. // set global entry pointer
  230. bunixsignal_selfpipe_entries[entry->signo] = entry;
  231. // install signal handler
  232. struct sigaction act;
  233. memset(&act, 0, sizeof(act));
  234. act.sa_handler = signal_handler;
  235. sigemptyset(&act.sa_mask);
  236. if (sigaction(entry->signo, &act, NULL) < 0) {
  237. BLog(BLOG_ERROR, "sigaction failed");
  238. goto loop_fail2;
  239. }
  240. o->num_entries++;
  241. continue;
  242. loop_fail2:
  243. BReactor_RemoveFileDescriptor(o->reactor, &entry->pipe_read_bfd);
  244. loop_fail1:
  245. ASSERT_FORCE(close(entry->pipefds[0]) == 0)
  246. ASSERT_FORCE(close(entry->pipefds[1]) == 0)
  247. loop_fail0:
  248. goto fail2;
  249. }
  250. #endif
  251. DebugObject_Init(&o->d_obj);
  252. return 1;
  253. #ifdef BADVPN_USE_SIGNALFD
  254. fail2:
  255. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  256. fail1:
  257. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  258. #endif
  259. #ifdef BADVPN_USE_KEVENT
  260. fail2:
  261. while (o->num_entries > 0) {
  262. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  263. o->num_entries--;
  264. }
  265. BFree(o->entries);
  266. #endif
  267. #ifdef BADVPN_USE_SELFPIPE
  268. fail2:
  269. while (o->num_entries > 0) {
  270. free_selfpipe_entry(&o->entries[o->num_entries - 1]);
  271. o->num_entries--;
  272. }
  273. BFree(o->entries);
  274. #endif
  275. fail0:
  276. return 0;
  277. }
  278. void BUnixSignal_Free (BUnixSignal *o, int unblock)
  279. {
  280. ASSERT(unblock == 0 || unblock == 1)
  281. DebugObject_Free(&o->d_obj);
  282. #ifdef BADVPN_USE_SIGNALFD
  283. if (unblock) {
  284. // unblock signals
  285. ASSERT_FORCE(sigprocmask(SIG_UNBLOCK, &o->signals, 0) == 0)
  286. }
  287. // free signalfd BFileDescriptor
  288. BReactor_RemoveFileDescriptor(o->reactor, &o->signalfd_bfd);
  289. // free signalfd fd
  290. ASSERT_FORCE(close(o->signalfd_fd) == 0)
  291. #endif
  292. #ifdef BADVPN_USE_KEVENT
  293. if (unblock) {
  294. // unblock signals
  295. ASSERT_FORCE(sigprocmask(SIG_UNBLOCK, &o->signals, 0) == 0)
  296. }
  297. // free kevents
  298. while (o->num_entries > 0) {
  299. BReactorKEvent_Free(&o->entries[o->num_entries - 1].kevent);
  300. o->num_entries--;
  301. }
  302. // free array
  303. BFree(o->entries);
  304. #endif
  305. #ifdef BADVPN_USE_SELFPIPE
  306. if (!unblock) {
  307. // block signals
  308. if (sigprocmask(SIG_BLOCK, &o->signals, 0) < 0) {
  309. BLog(BLOG_ERROR, "sigprocmask block failed");
  310. }
  311. }
  312. // free entries
  313. while (o->num_entries > 0) {
  314. free_selfpipe_entry(&o->entries[o->num_entries - 1]);
  315. o->num_entries--;
  316. }
  317. // free array
  318. BFree(o->entries);
  319. #endif
  320. }