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: 6e889f26d1449bdb79eab8cb380659f090f395a6 $
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: 6e889f26d1449bdb79eab8cb380659f090f395a6 $")
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) fr_exit(0);
101 }
102 
103 static void main_loop_signal_process(int flag)
104 {
105  if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
106  if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
107  INFO("Signalled to exit");
109  } else {
110  INFO("Signalled to terminate");
112  }
113 
114  return;
115  } /* else exit/term flags weren't set */
116 
117  /*
118  * Tell the even loop to stop processing.
119  */
120  if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
121  fr_time_t when;
122  static fr_time_t last_hup = fr_time_wrap(0);
123 
124  when = fr_time();
125  if (fr_time_delta_lt(fr_time_sub(when, last_hup), fr_time_delta_from_sec(5))) {
126  INFO("Ignoring HUP (less than 5s since last one)");
127  return;
128  }
129 
130  INFO("Received HUP signal");
131 
132  last_hup = when;
133 
134  trigger_exec(unlang_interpret_get_thread_default(), NULL, "server.signal.hup", true, NULL);
136  }
137 }
138 
139 /** I/O handler listening on the signal pipe
140  *
141  */
143  UNUSED int fd, UNUSED int flags, UNUSED void *ctx)
144 {
145  ssize_t i, rcode;
146  uint8_t buffer[32];
147 
148  rcode = read(self_pipe[0], buffer, sizeof(buffer));
149  if (rcode <= 0) return;
150 
151  /*
152  * Merge pending signals.
153  */
154  for (i = 0; i < rcode; i++) buffer[0] |= buffer[i];
155 
157 }
158 
159 /** Return the main loop event list
160  *
161  */
163 {
164  return event_list;
165 }
166 
167 #ifdef HAVE_SYSTEMD_WATCHDOG
168 void main_loop_set_sd_watchdog_interval(void)
169 {
170  uint64_t interval_usec;
171 
172  if (sd_watchdog_enabled(0, &interval_usec) > 0) {
173  /*
174  * Convert microseconds to nanoseconds
175  * and set the interval to be half what
176  * systemd uses as its timeout value.
177  */
178  sd_watchdog_interval = fr_time_delta_wrap((interval_usec * 1000) / 2);
179 
180  INFO("systemd watchdog interval is %pVs", fr_box_time_delta(sd_watchdog_interval));
181  } else {
182  INFO("systemd watchdog is disabled");
183  }
184 }
185 #endif
186 
187 void main_loop_free(void)
188 {
189  TALLOC_FREE(event_list);
190 }
191 
193 {
194  int ret;
195 
196 #ifdef HAVE_SYSTEMD_WATCHDOG
197  bool under_systemd = (getenv("NOTIFY_SOCKET") != NULL);
198 #endif
199 
200  if (!event_list) return 0;
201 
202 #ifdef HAVE_SYSTEMD_WATCHDOG
203  /*
204  * Tell systemd we're ready!
205  */
206  if (under_systemd) sd_notify(0, "READY=1");
207 
208  /*
209  * Start placating the watchdog (if told to do so).
210  */
211  if (fr_time_delta_ispos(sd_watchdog_interval)) sd_watchdog_event(event_list, fr_time_wrap(0), NULL);
212 #endif
213 
214  ret = fr_event_loop(event_list);
215 #ifdef HAVE_SYSTEMD_WATCHDOG
216  if (ret != 0x80) { /* Not HUP */
217  if (under_systemd) {
218  INFO("Informing systemd we're stopping");
219  sd_notify(0, "STOPPING=1");
220  fr_event_timer_delete(&sd_watchdog_ev);
221  }
222  }
223 #endif
224 
225  /*
226  * Clear up the signal pipe we created in
227  * main loop init.
228  */
230  close(self_pipe[0]);
231 
232  return ret;
233 }
234 
235 static int _loop_status(UNUSED fr_time_t now, fr_time_delta_t wake, UNUSED void *ctx)
236 {
237  if (fr_time_delta_unwrap(wake) > (NSEC / 10)) DEBUG3("Main loop waking up in %pV seconds", fr_box_time_delta(wake));
238 
239  return 0;
240 }
241 
242 /** Initialise the main event loop, setting up signal handlers
243  *
244  * This has to be done post-fork in case we're using kqueue, where the
245  * queue isn't inherited by the child process.
246  *
247  * @return
248  * - 0 on success.
249  * - -1 on failure.
250  */
251 int main_loop_init(void)
252 {
253  event_list = fr_event_list_alloc(NULL, _loop_status, NULL); /* Must not be allocated in mprotected ctx */
254  if (!event_list) return -1;
255 
256  /*
257  * Not actually running the server, just exit.
258  */
259  if (check_config) return 0;
260 
261  /*
262  * Child threads need a pipe to signal us, as do the
263  * signal handlers.
264  */
265  if (pipe(self_pipe) < 0) {
266  ERROR("Error opening self-signal pipe: %s", fr_syserror(errno));
267  return -1;
268  }
269  if ((fcntl(self_pipe[0], F_SETFL, O_NONBLOCK) < 0) ||
270  (fcntl(self_pipe[0], F_SETFD, FD_CLOEXEC) < 0)) {
271  ERROR("Error setting self-signal pipe flags: %s", fr_syserror(errno));
272  return -1;
273  }
274  if ((fcntl(self_pipe[1], F_SETFL, O_NONBLOCK) < 0) ||
275  (fcntl(self_pipe[1], F_SETFD, FD_CLOEXEC) < 0)) {
276  ERROR("Error setting self-signal pipe flags: %s", fr_syserror(errno));
277  return -1;
278  }
279  DEBUG4("Created self-signal pipe. Read end FD %i, write end FD %i", self_pipe[0], self_pipe[1]);
280 
281  if (fr_event_fd_insert(NULL, NULL, event_list, self_pipe[0],
283  NULL,
284  NULL,
285  event_list) < 0) {
286  PERROR("Failed creating self-signal pipe handler");
287  return -1;
288  }
289 
290  return 0;
291 }
292 
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
bool check_config
Definition: cf_file.c:66
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition: debug.h:226
#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:1768
#define PERROR(_fmt,...)
Definition: log.h:228
#define DEBUG3(_fmt,...)
Definition: log.h:266
#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:2892
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition: event.c:1604
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition: event.c:2737
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:1253
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition: event.c:2759
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:192
static void main_loop_signal_process(int flag)
Definition: main_loop.c:103
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:235
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition: main_loop.c:162
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:142
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition: main_loop.c:251
void main_loop_free(void)
Definition: main_loop.c:187
@ 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:283
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
#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:288
#define NSEC
Definition: time.h:377
#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:280
close(uq->fd)
#define fr_box_time_delta(_val)
Definition: value.h:336