The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
main_loop.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 6d2e28c463485709e1f215e66c6ab12f65b96bd7 $
19  *
20  * @file lib/server/main_loop.c
21  * @brief Creates a global event loop, and manages signalling between the forked child
22  * and its parent as the server starts.
23  *
24  * @copyright 2012 The FreeRADIUS server project
25  * @copyright 2012 Alan DeKok (aland@deployingradius.com)
26  */
27 
28 RCSID("$Id: 6d2e28c463485709e1f215e66c6ab12f65b96bd7 $")
29 
30 #include <freeradius-devel/server/cf_parse.h>
31 #include <freeradius-devel/server/main_loop.h>
32 #include <freeradius-devel/util/debug.h>
33 #include <freeradius-devel/server/state.h>
34 #include <freeradius-devel/server/trigger.h>
35 #include <freeradius-devel/server/util.h>
36 
37 #include <freeradius-devel/util/misc.h>
38 #include <freeradius-devel/util/syserror.h>
39 
40 #include <signal.h>
41 #include <fcntl.h>
42 
43 #ifdef HAVE_SYS_WAIT_H
44 # include <sys/wait.h>
45 #endif
46 
47 extern pid_t radius_pid;
48 static fr_event_list_t *event_list = NULL;
49 static int self_pipe[2] = { -1, -1 };
50 
51 #ifdef HAVE_SYSTEMD_WATCHDOG
52 #include <systemd/sd-daemon.h>
53 
54 static fr_time_delta_t sd_watchdog_interval;
55 static fr_event_timer_t const *sd_watchdog_ev;
56 
57 /** Reoccurring watchdog event to inform systemd we're still alive
58  *
59  * Note actually a very good indicator of aliveness as the main event
60  * loop doesn't actually do any packet processing.
61  */
62 static void sd_watchdog_event(fr_event_list_t *our_el, UNUSED fr_time_t now, void *ctx)
63 {
64  DEBUG("Emitting systemd watchdog notification");
65 
66  sd_notify(0, "WATCHDOG=1");
67 
68  if (fr_event_timer_in(NULL, our_el, &sd_watchdog_ev,
69  sd_watchdog_interval,
70  sd_watchdog_event, ctx) < 0) {
71  ERROR("Failed to insert watchdog event");
72  }
73 }
74 #endif
75 
76 /*
77  * Inform ourselves that we received a signal.
78  */
79 void main_loop_signal_raise(int flag)
80 {
81  ssize_t rcode;
82  uint8_t buffer[16];
83 
84  /*
85  * The read MUST be non-blocking for this to work.
86  */
87  rcode = read(self_pipe[0], buffer, sizeof(buffer));
88  if (rcode > 0) {
89  ssize_t i;
90 
91  for (i = 0; i < rcode; i++) {
92  buffer[0] |= buffer[i];
93  }
94  } else {
95  buffer[0] = 0;
96  }
97 
98  buffer[0] |= flag;
99 
100  if (write(self_pipe[1], buffer, 1) < 0) {
101  FR_FAULT_LOG("Failed to write to self-pipe: %s", fr_syserror(errno));
102  fr_exit(0);
103  }
104 }
105 
106 static void main_loop_signal_process(int flag)
107 {
108  if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
109  if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
110  INFO("Signalled to exit");
112  } else {
113  INFO("Signalled to terminate");
115  }
116 
117  return;
118  } /* else exit/term flags weren't set */
119 
120  /*
121  * Tell the even loop to stop processing.
122  */
123  if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
124  fr_time_t when;
125  static fr_time_t last_hup = fr_time_wrap(0);
126 
127  when = fr_time();
128  if (fr_time_delta_lt(fr_time_sub(when, last_hup), fr_time_delta_from_sec(5))) {
129  INFO("Ignoring HUP (less than 5s since last one)");
130  return;
131  }
132 
133  INFO("Received HUP signal");
134 
135  last_hup = when;
136 
137  trigger_exec(unlang_interpret_get_thread_default(), NULL, "server.signal.hup", true, NULL);
139  }
140 }
141 
142 /** I/O handler listening on the signal pipe
143  *
144  */
146  UNUSED int fd, UNUSED int flags, UNUSED void *ctx)
147 {
148  ssize_t i, rcode;
149  uint8_t buffer[32];
150 
151  rcode = read(self_pipe[0], buffer, sizeof(buffer));
152  if (rcode <= 0) return;
153 
154  /*
155  * Merge pending signals.
156  */
157  for (i = 0; i < rcode; i++) buffer[0] |= buffer[i];
158 
160 }
161 
162 /** Return the main loop event list
163  *
164  */
166 {
167  return event_list;
168 }
169 
170 #ifdef HAVE_SYSTEMD_WATCHDOG
171 void main_loop_set_sd_watchdog_interval(void)
172 {
173  uint64_t interval_usec;
174 
175  if (sd_watchdog_enabled(0, &interval_usec) > 0) {
176  /*
177  * Convert microseconds to nanoseconds
178  * and set the interval to be half what
179  * systemd uses as its timeout value.
180  */
181  sd_watchdog_interval = fr_time_delta_wrap((interval_usec * 1000) / 2);
182 
183  INFO("systemd watchdog interval is %pVs", fr_box_time_delta(sd_watchdog_interval));
184  } else {
185  INFO("systemd watchdog is disabled");
186  }
187 }
188 #endif
189 
190 void main_loop_free(void)
191 {
192  TALLOC_FREE(event_list);
193 }
194 
196 {
197  int ret;
198 
199 #ifdef HAVE_SYSTEMD_WATCHDOG
200  bool under_systemd = (getenv("NOTIFY_SOCKET") != NULL);
201 #endif
202 
203  if (!event_list) return 0;
204 
205 #ifdef HAVE_SYSTEMD_WATCHDOG
206  /*
207  * Tell systemd we're ready!
208  */
209  if (under_systemd) sd_notify(0, "READY=1");
210 
211  /*
212  * Start placating the watchdog (if told to do so).
213  */
214  if (fr_time_delta_ispos(sd_watchdog_interval)) sd_watchdog_event(event_list, fr_time_wrap(0), NULL);
215 #endif
216 
217  ret = fr_event_loop(event_list);
218 #ifdef HAVE_SYSTEMD_WATCHDOG
219  if (ret != 0x80) { /* Not HUP */
220  if (under_systemd) {
221  INFO("Informing systemd we're stopping");
222  sd_notify(0, "STOPPING=1");
223  fr_event_timer_delete(&sd_watchdog_ev);
224  }
225  }
226 #endif
227 
228  /*
229  * Clear up the signal pipe we created in
230  * main loop init.
231  */
233  close(self_pipe[0]);
234 
235  return ret;
236 }
237 
238 static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
239 {
240  if (fr_time_delta_unwrap(wake) > (NSEC / 10)) DEBUG4("Main loop waking up in %pV seconds", fr_box_time_delta(wake));
241 
242  return 0;
243 }
244 
245 /** Initialise the main event loop, setting up signal handlers
246  *
247  * This has to be done post-fork in case we're using kqueue, where the
248  * queue isn't inherited by the child process.
249  *
250  * @return
251  * - 0 on success.
252  * - -1 on failure.
253  */
254 int main_loop_init(void)
255 {
256  event_list = fr_event_list_alloc(NULL, _loop_status, NULL); /* Must not be allocated in mprotected ctx */
257  if (!event_list) return -1;
258 
259  /*
260  * Not actually running the server, just exit.
261  */
262  if (check_config) return 0;
263 
264  /*
265  * Child threads need a pipe to signal us, as do the
266  * signal handlers.
267  */
268  if (pipe(self_pipe) < 0) {
269  ERROR("Error opening self-signal pipe: %s", fr_syserror(errno));
270  return -1;
271  }
272  if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
273  (fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
274  ERROR("Error setting self-signal pipe flags: %s", fr_syserror(errno));
275  return -1;
276  }
277  if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
278  (fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
279  ERROR("Error setting self-signal pipe flags: %s", fr_syserror(errno));
280  return -1;
281  }
282  DEBUG4("Created self-signal pipe. Read end FD %i, write end FD %i", self_pipe[0], self_pipe[1]);
283 
284  if (fr_event_fd_insert(NULL, NULL, event_list, self_pipe[0],
286  NULL,
287  NULL,
288  event_list) < 0) {
289  PERROR("Failed creating self-signal pipe handler");
290  return -1;
291  }
292 
293  return 0;
294 }
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:481
#define UNUSED
Definition: build.h:313
bool check_config
Definition: cf_file.c:67
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition: debug.h:228
#define FR_FAULT_LOG(_fmt,...)
Definition: debug.h:49
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
#define fr_event_fd_insert(...)
Definition: event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition: event.h:62
#define fr_event_timer_in(...)
Definition: event.h:255
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition: interpret.c:1787
#define PERROR(_fmt,...)
Definition: log.h:228
#define DEBUG4(_fmt,...)
Definition: log.h:267
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition: event.c:2899
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition: event.c:1611
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition: event.c:2744
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition: event.c:1260
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition: event.c:2766
Stores all information relating to an event list.
Definition: event.c:411
A timer event.
Definition: event.c:102
static int self_pipe[2]
Definition: main_loop.c:49
int main_loop_start(void)
Definition: main_loop.c:195
static void main_loop_signal_process(int flag)
Definition: main_loop.c:106
static fr_event_list_t * event_list
Definition: main_loop.c:48
static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
Definition: main_loop.c:238
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition: main_loop.c:165
void main_loop_signal_raise(int flag)
Definition: main_loop.c:79
pid_t radius_pid
static void main_loop_signal_recv(UNUSED fr_event_list_t *xel, UNUSED int fd, UNUSED int flags, UNUSED void *ctx)
I/O handler listening on the signal pipe.
Definition: main_loop.c:145
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition: main_loop.c:254
void main_loop_free(void)
Definition: main_loop.c:190
@ RADIUS_SIGNAL_SELF_HUP
Definition: main_loop.h:36
@ RADIUS_SIGNAL_SELF_EXIT
Definition: main_loop.h:38
@ RADIUS_SIGNAL_SELF_TERM
Definition: main_loop.h:37
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define INFO(fmt,...)
Definition: radict.c:54
#define FD_CLOEXEC
Signals that can be sent to a request.
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition: time.h:154
#define fr_time_delta_lt(_a, _b)
Definition: time.h:285
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:590
#define fr_time_delta_wrap(_time)
Definition: time.h:152
#define fr_time_wrap(_time)
Definition: time.h:145
#define fr_time_delta_ispos(_a)
Definition: time.h:290
#define NSEC
Definition: time.h:379
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition: time.h:229
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
"server local" time.
Definition: time.h:69
int trigger_exec(unlang_interpret_t *intp, CONF_SECTION const *cs, char const *name, bool rate_limit, fr_pair_list_t *args)
Execute a trigger - call an executable to process an event.
Definition: trigger.c:233
close(uq->fd)
#define fr_box_time_delta(_val)
Definition: value.h:343