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
37volatile static unsigned long long pending_signals;
38
39void engine_set_terminal_attributes (void) __attribute__ ((weak));
40void engine_set_terminal_attributes (void) {}
41
42/* {{{ PENDING SIGNALS */
43
44void signal_set_pending (int sig) {
45 __sync_fetch_and_or (&pending_signals, SIG2INT(sig));
46}
47
48int signal_check_pending (int sig) {
49 return (pending_signals & SIG2INT(sig)) != 0;
50}
51
52int 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
61void 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
69void 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
77void 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
85void 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
93static const char sig_message[] = "received signal ??\n";
94
95void 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
108void 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
125void empty_signal_handler (const int sig) {}
126
127int interrupt_signal_raised (void) /* {{{ */ {
128 return (pending_signals & SIG_INTERRUPT_MASK) != 0;
129}
130/* }}} */
131
132
133int 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