1 | /* |
2 | This file is part of Mtproto-proxy Library. |
3 | |
4 | Mtproto-proxy Library is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU Lesser General Public License as published by |
6 | the Free Software Foundation, either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | Mtproto-proxy Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | Copyright 2013 Vkontakte Ltd |
18 | 2013 Vitaliy Valtman |
19 | 2013 Anton Maydell |
20 | |
21 | Copyright 2014 Telegram Messenger Inc |
22 | 2014 Vitaly Valtman |
23 | 2014 Anton Maydell |
24 | |
25 | Copyright 2015-2016 Telegram Messenger Inc |
26 | 2015-2016 Vitaliy Valtman |
27 | */ |
28 | #include <signal.h> |
29 | #include <unistd.h> |
30 | |
31 | #include "common/kprintf.h" |
32 | #include "common/server-functions.h" |
33 | |
34 | #include "engine/engine.h" |
35 | #include "engine/engine-signals.h" |
36 | |
37 | volatile static unsigned long long pending_signals; |
38 | |
39 | void engine_set_terminal_attributes (void) __attribute__ ((weak)); |
40 | void engine_set_terminal_attributes (void) {} |
41 | |
42 | /* {{{ PENDING SIGNALS */ |
43 | |
44 | void signal_set_pending (int sig) { |
45 | __sync_fetch_and_or (&pending_signals, SIG2INT(sig)); |
46 | } |
47 | |
48 | int signal_check_pending (int sig) { |
49 | return (pending_signals & SIG2INT(sig)) != 0; |
50 | } |
51 | |
52 | int signal_check_pending_and_clear (int sig) { |
53 | int res = (pending_signals & SIG2INT(sig)) != 0; |
54 | if (res) { |
55 | __sync_fetch_and_and (&pending_signals, ~SIG2INT(sig)); |
56 | } |
57 | return res; |
58 | } |
59 | /* }}} */ |
60 | |
61 | void sigint_immediate_handler (const int sig) /* {{{ */ { |
62 | static const char message[] = "SIGINT handled immediately.\n" ; |
63 | kwrite (2, message, sizeof (message) - (size_t)1); |
64 | engine_set_terminal_attributes (); |
65 | _exit (1); |
66 | } |
67 | /* }}} */ |
68 | |
69 | void sigterm_immediate_handler (const int sig) /* {{{ */ { |
70 | static const char message[] = "SIGTERM handled immediately.\n" ; |
71 | kwrite (2, message, sizeof (message) - (size_t) 1); |
72 | engine_set_terminal_attributes (); |
73 | _exit (1); |
74 | } |
75 | /* }}} */ |
76 | |
77 | void sigint_handler (const int sig) /* {{{ */ { |
78 | static const char message[] = "SIGINT handled.\n" ; |
79 | kwrite (2, message, sizeof (message) - (size_t) 1); |
80 | signal_set_pending (SIGINT); |
81 | ksignal (sig, sigint_immediate_handler); |
82 | } |
83 | /* }}} */ |
84 | |
85 | void sigterm_handler (const int sig) /* {{{ */ { |
86 | static const char message[] = "SIGTERM handled.\n" ; |
87 | kwrite (2, message, sizeof (message) - (size_t) 1); |
88 | signal_set_pending (SIGTERM); |
89 | ksignal (sig, sigterm_immediate_handler); |
90 | } |
91 | /* }}} */ |
92 | |
93 | static const char sig_message[] = "received signal ??\n" ; |
94 | |
95 | void default_signal_handler (const int sig) /* {{{ */ { |
96 | char msg[sizeof (sig_message)]; |
97 | int i; |
98 | for (i = 0; i < sizeof (sig_message); i++) { |
99 | msg[i] = sig_message[i]; |
100 | } |
101 | msg[sizeof (sig_message) - 4] = '0' + (sig / 10); |
102 | msg[sizeof (sig_message) - 3] = '0' + (sig % 10); |
103 | kwrite (2, msg, sizeof (sig_message) - (size_t) 1); |
104 | |
105 | signal_set_pending (sig); |
106 | } |
107 | |
108 | void quiet_signal_handler (const int sig) { |
109 | if (verbosity >= 1) { |
110 | char msg[sizeof (sig_message)]; |
111 | int i; |
112 | for (i = 0; i < sizeof (sig_message); i++) { |
113 | msg[i] = sig_message[i]; |
114 | } |
115 | msg[sizeof (sig_message) - 4] = '0' + (sig / 10); |
116 | msg[sizeof (sig_message) - 3] = '0' + (sig % 10); |
117 | kwrite (2, msg, sizeof (sig_message) - (size_t) 1); |
118 | } |
119 | |
120 | signal_set_pending (sig); |
121 | } |
122 | |
123 | /* }}} */ |
124 | |
125 | void empty_signal_handler (const int sig) {} |
126 | |
127 | int interrupt_signal_raised (void) /* {{{ */ { |
128 | return (pending_signals & SIG_INTERRUPT_MASK) != 0; |
129 | } |
130 | /* }}} */ |
131 | |
132 | |
133 | int engine_process_signals (void) /* {{{ */ { |
134 | engine_t *E = engine_state; |
135 | server_functions_t *F = E->F; |
136 | |
137 | long long allowed = F->allowed_signals; |
138 | long long forbidden = 0; |
139 | while (1) { |
140 | long long t = allowed & pending_signals & ~forbidden; |
141 | if (!t) { |
142 | break; |
143 | } |
144 | int i = __builtin_ctzll (t); |
145 | if (!i) { |
146 | i += 64; |
147 | } |
148 | assert (F->signal_handlers[i]); |
149 | if (signal_check_pending_and_clear (i)) { |
150 | F->signal_handlers[i] (); |
151 | } |
152 | forbidden |= SIG2INT(i); |
153 | } |
154 | |
155 | return 1; |
156 | } |
157 | /* }}} */ |
158 | |