BUnixSignal.c 11 KB

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