BadVPN – Blame information for rev 1

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