1 |
|
|
/* $OpenBSD: isakmpd.c,v 1.104 2016/04/02 14:37:42 krw Exp $ */ |
2 |
|
|
/* $EOM: isakmpd.c,v 1.54 2000/10/05 09:28:22 niklas Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. |
6 |
|
|
* Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. |
7 |
|
|
* Copyright (c) 1999, 2000, 2001 Håkan Olsson. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
|
* modification, are permitted provided that the following conditions |
11 |
|
|
* are met: |
12 |
|
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
|
* documentation and/or other materials provided with the distribution. |
17 |
|
|
* |
18 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 |
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 |
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 |
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 |
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 |
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 |
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 |
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 |
|
|
*/ |
29 |
|
|
|
30 |
|
|
/* |
31 |
|
|
* This code was written under funding by Ericsson Radio Systems. |
32 |
|
|
*/ |
33 |
|
|
|
34 |
|
|
#include <errno.h> |
35 |
|
|
#include <sys/types.h> |
36 |
|
|
#include <sys/stat.h> |
37 |
|
|
#include <signal.h> |
38 |
|
|
#include <stdio.h> |
39 |
|
|
#include <stdlib.h> |
40 |
|
|
#include <string.h> |
41 |
|
|
#include <time.h> |
42 |
|
|
#include <netdb.h> |
43 |
|
|
#include <unistd.h> |
44 |
|
|
#include <fcntl.h> |
45 |
|
|
#include <paths.h> |
46 |
|
|
|
47 |
|
|
#include "app.h" |
48 |
|
|
#include "conf.h" |
49 |
|
|
#include "connection.h" |
50 |
|
|
#include "init.h" |
51 |
|
|
#include "libcrypto.h" |
52 |
|
|
#include "log.h" |
53 |
|
|
#include "message.h" |
54 |
|
|
#include "monitor.h" |
55 |
|
|
#include "nat_traversal.h" |
56 |
|
|
#include "sa.h" |
57 |
|
|
#include "timer.h" |
58 |
|
|
#include "transport.h" |
59 |
|
|
#include "udp.h" |
60 |
|
|
#include "udp_encap.h" |
61 |
|
|
#include "ui.h" |
62 |
|
|
#include "util.h" |
63 |
|
|
#include "cert.h" |
64 |
|
|
|
65 |
|
|
#include "policy.h" |
66 |
|
|
|
67 |
|
|
static void usage(void); |
68 |
|
|
|
69 |
|
|
/* |
70 |
|
|
* Set if -d is given, currently just for running in the foreground and log |
71 |
|
|
* to stderr instead of syslog. |
72 |
|
|
*/ |
73 |
|
|
int debug = 0; |
74 |
|
|
|
75 |
|
|
/* Set when no policy file shall be used. */ |
76 |
|
|
int acquire_only = 0; |
77 |
|
|
|
78 |
|
|
/* Set when SAs shall be deleted on shutdown. */ |
79 |
|
|
int delete_sas = 1; |
80 |
|
|
|
81 |
|
|
/* |
82 |
|
|
* If we receive a SIGHUP signal, this flag gets set to show we need to |
83 |
|
|
* reconfigure ASAP. |
84 |
|
|
*/ |
85 |
|
|
volatile sig_atomic_t sighupped = 0; |
86 |
|
|
|
87 |
|
|
/* |
88 |
|
|
* If we receive a USR1 signal, this flag gets set to show we need to dump |
89 |
|
|
* a report over our internal state ASAP. The file to report to is settable |
90 |
|
|
* via the -R parameter. |
91 |
|
|
*/ |
92 |
|
|
volatile sig_atomic_t sigusr1ed = 0; |
93 |
|
|
static char *report_file = "/var/run/isakmpd.report"; |
94 |
|
|
|
95 |
|
|
/* |
96 |
|
|
* If we receive a TERM signal, perform a "clean shutdown" of the daemon. |
97 |
|
|
* This includes to send DELETE notifications for all our active SAs. |
98 |
|
|
* Also on recv of an INT signal (Ctrl-C out of an '-d' session, typically). |
99 |
|
|
*/ |
100 |
|
|
volatile sig_atomic_t sigtermed = 0; |
101 |
|
|
void daemon_shutdown_now(int); |
102 |
|
|
void set_slave_signals(void); |
103 |
|
|
void sanitise_stdfd(void); |
104 |
|
|
|
105 |
|
|
/* The default path of the PID file. */ |
106 |
|
|
char *pid_file = "/var/run/isakmpd.pid"; |
107 |
|
|
|
108 |
|
|
/* The path of the IKE packet capture log file. */ |
109 |
|
|
static char *pcap_file = 0; |
110 |
|
|
|
111 |
|
|
static void |
112 |
|
|
usage(void) |
113 |
|
|
{ |
114 |
|
|
extern char *__progname; |
115 |
|
|
|
116 |
|
|
fprintf(stderr, |
117 |
|
|
"usage: %s [-46adKLnSTv] [-c config-file] [-D class=level] [-f fifo]\n" |
118 |
|
|
" [-i pid-file] [-l packetlog-file] [-N udpencap-port]\n" |
119 |
|
|
" [-p listen-port] [-R report-file]\n", |
120 |
|
|
__progname); |
121 |
|
|
exit(1); |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
static void |
125 |
|
|
parse_args(int argc, char *argv[]) |
126 |
|
|
{ |
127 |
|
|
int ch; |
128 |
|
|
int cls, level; |
129 |
|
|
int do_packetlog = 0; |
130 |
|
|
|
131 |
|
|
while ((ch = getopt(argc, argv, "46ac:dD:f:i:KnN:p:Ll:R:STv")) != -1) { |
132 |
|
|
switch (ch) { |
133 |
|
|
case '4': |
134 |
|
|
bind_family |= BIND_FAMILY_INET4; |
135 |
|
|
break; |
136 |
|
|
|
137 |
|
|
case '6': |
138 |
|
|
bind_family |= BIND_FAMILY_INET6; |
139 |
|
|
break; |
140 |
|
|
|
141 |
|
|
case 'a': |
142 |
|
|
acquire_only = 1; |
143 |
|
|
break; |
144 |
|
|
|
145 |
|
|
case 'c': |
146 |
|
|
conf_path = optarg; |
147 |
|
|
break; |
148 |
|
|
|
149 |
|
|
case 'd': |
150 |
|
|
debug++; |
151 |
|
|
break; |
152 |
|
|
|
153 |
|
|
case 'D': |
154 |
|
|
if (sscanf(optarg, "%d=%d", &cls, &level) != 2) { |
155 |
|
|
if (sscanf(optarg, "A=%d", &level) == 1) { |
156 |
|
|
for (cls = 0; cls < LOG_ENDCLASS; |
157 |
|
|
cls++) |
158 |
|
|
log_debug_cmd(cls, level); |
159 |
|
|
} else |
160 |
|
|
log_print("parse_args: -D argument " |
161 |
|
|
"unparseable: %s", optarg); |
162 |
|
|
} else |
163 |
|
|
log_debug_cmd(cls, level); |
164 |
|
|
break; |
165 |
|
|
|
166 |
|
|
case 'f': |
167 |
|
|
ui_fifo = optarg; |
168 |
|
|
break; |
169 |
|
|
|
170 |
|
|
case 'i': |
171 |
|
|
pid_file = optarg; |
172 |
|
|
break; |
173 |
|
|
|
174 |
|
|
case 'K': |
175 |
|
|
ignore_policy++; |
176 |
|
|
break; |
177 |
|
|
|
178 |
|
|
case 'n': |
179 |
|
|
app_none++; |
180 |
|
|
break; |
181 |
|
|
|
182 |
|
|
case 'N': |
183 |
|
|
udp_encap_default_port = optarg; |
184 |
|
|
break; |
185 |
|
|
|
186 |
|
|
case 'p': |
187 |
|
|
udp_default_port = optarg; |
188 |
|
|
break; |
189 |
|
|
|
190 |
|
|
case 'l': |
191 |
|
|
pcap_file = optarg; |
192 |
|
|
/* FALLTHROUGH */ |
193 |
|
|
|
194 |
|
|
case 'L': |
195 |
|
|
do_packetlog++; |
196 |
|
|
break; |
197 |
|
|
|
198 |
|
|
case 'R': |
199 |
|
|
report_file = optarg; |
200 |
|
|
break; |
201 |
|
|
|
202 |
|
|
case 'S': |
203 |
|
|
delete_sas = 0; |
204 |
|
|
ui_daemon_passive = 1; |
205 |
|
|
break; |
206 |
|
|
|
207 |
|
|
case 'T': |
208 |
|
|
disable_nat_t = 1; |
209 |
|
|
break; |
210 |
|
|
|
211 |
|
|
case 'v': |
212 |
|
|
verbose_logging = 1; |
213 |
|
|
break; |
214 |
|
|
|
215 |
|
|
case '?': |
216 |
|
|
default: |
217 |
|
|
usage(); |
218 |
|
|
} |
219 |
|
|
} |
220 |
|
|
argc -= optind; |
221 |
|
|
argv += optind; |
222 |
|
|
|
223 |
|
|
if (argc > 0) |
224 |
|
|
usage(); |
225 |
|
|
|
226 |
|
|
if (do_packetlog && !pcap_file) |
227 |
|
|
pcap_file = PCAP_FILE_DEFAULT; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
/* ARGSUSED */ |
231 |
|
|
static void |
232 |
|
|
sighup(int sig) |
233 |
|
|
{ |
234 |
|
|
sighupped = 1; |
235 |
|
|
} |
236 |
|
|
|
237 |
|
|
/* Report internal state on SIGUSR1. */ |
238 |
|
|
static void |
239 |
|
|
report(void) |
240 |
|
|
{ |
241 |
|
|
FILE *rfp, *old; |
242 |
|
|
mode_t old_umask; |
243 |
|
|
|
244 |
|
|
old_umask = umask(S_IRWXG | S_IRWXO); |
245 |
|
|
rfp = monitor_fopen(report_file, "w"); |
246 |
|
|
umask(old_umask); |
247 |
|
|
|
248 |
|
|
if (!rfp) { |
249 |
|
|
log_error("report: fopen (\"%s\", \"w\") failed", report_file); |
250 |
|
|
return; |
251 |
|
|
} |
252 |
|
|
/* Divert the log channel to the report file during the report. */ |
253 |
|
|
old = log_current(); |
254 |
|
|
log_to(rfp); |
255 |
|
|
ui_report("r"); |
256 |
|
|
log_to(old); |
257 |
|
|
fclose(rfp); |
258 |
|
|
} |
259 |
|
|
|
260 |
|
|
static void |
261 |
|
|
sigusr1(int sig) |
262 |
|
|
{ |
263 |
|
|
sigusr1ed = 1; |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
static int |
267 |
|
|
phase2_sa_check(struct sa *sa, void *arg) |
268 |
|
|
{ |
269 |
|
|
return sa->phase == 2; |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
static int |
273 |
|
|
phase1_sa_check(struct sa *sa, void *arg) |
274 |
|
|
{ |
275 |
|
|
return sa->phase == 1; |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
void |
279 |
|
|
set_slave_signals(void) |
280 |
|
|
{ |
281 |
|
|
int n; |
282 |
|
|
|
283 |
|
|
for (n = 1; n < _NSIG; n++) |
284 |
|
|
signal(n, SIG_DFL); |
285 |
|
|
|
286 |
|
|
/* |
287 |
|
|
* Do a clean daemon shutdown on TERM/INT. These signals must be |
288 |
|
|
* initialized before monitor_init(). INT is only used with '-d'. |
289 |
|
|
*/ |
290 |
|
|
signal(SIGTERM, daemon_shutdown_now); |
291 |
|
|
if (debug == 1) /* i.e '-dd' will skip this. */ |
292 |
|
|
signal(SIGINT, daemon_shutdown_now); |
293 |
|
|
|
294 |
|
|
/* Reinitialize on HUP reception. */ |
295 |
|
|
signal(SIGHUP, sighup); |
296 |
|
|
|
297 |
|
|
/* Report state on USR1 reception. */ |
298 |
|
|
signal(SIGUSR1, sigusr1); |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
static void |
302 |
|
|
daemon_shutdown(void) |
303 |
|
|
{ |
304 |
|
|
/* Perform a (protocol-wise) clean shutdown of the daemon. */ |
305 |
|
|
struct sa *sa; |
306 |
|
|
|
307 |
|
|
if (sigtermed == 1) { |
308 |
|
|
log_print("isakmpd: shutting down..."); |
309 |
|
|
|
310 |
|
|
if (delete_sas && |
311 |
|
|
strncmp("no", conf_get_str("General", "Delete-SAs"), 2)) { |
312 |
|
|
/* |
313 |
|
|
* Delete all active SAs. First IPsec SAs, then |
314 |
|
|
* ISAKMPD. Each DELETE is another (outgoing) message. |
315 |
|
|
*/ |
316 |
|
|
while ((sa = sa_find(phase2_sa_check, NULL))) |
317 |
|
|
sa_delete(sa, 1); |
318 |
|
|
|
319 |
|
|
while ((sa = sa_find(phase1_sa_check, NULL))) |
320 |
|
|
sa_delete(sa, 1); |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
/* We only want to do this once. */ |
324 |
|
|
sigtermed++; |
325 |
|
|
} |
326 |
|
|
if (transport_prio_sendqs_empty()) { |
327 |
|
|
/* |
328 |
|
|
* When the prioritized transport sendq:s are empty, i.e all |
329 |
|
|
* the DELETE notifications have been sent, we can shutdown. |
330 |
|
|
*/ |
331 |
|
|
|
332 |
|
|
log_packet_stop(); |
333 |
|
|
log_print("isakmpd: exit"); |
334 |
|
|
exit(0); |
335 |
|
|
} |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
/* Called on SIGTERM, SIGINT or by ui_shutdown_daemon(). */ |
339 |
|
|
/* ARGSUSED */ |
340 |
|
|
void |
341 |
|
|
daemon_shutdown_now(int sig) |
342 |
|
|
{ |
343 |
|
|
sigtermed = 1; |
344 |
|
|
} |
345 |
|
|
|
346 |
|
|
/* Write pid file. */ |
347 |
|
|
static void |
348 |
|
|
write_pid_file(void) |
349 |
|
|
{ |
350 |
|
|
FILE *fp; |
351 |
|
|
|
352 |
|
|
unlink(pid_file); |
353 |
|
|
|
354 |
|
|
fp = fopen(pid_file, "w"); |
355 |
|
|
if (fp != NULL) { |
356 |
|
|
if (fprintf(fp, "%ld\n", (long) getpid()) < 0) |
357 |
|
|
log_error("write_pid_file: failed to write PID to " |
358 |
|
|
"\"%.100s\"", pid_file); |
359 |
|
|
fclose(fp); |
360 |
|
|
} else |
361 |
|
|
log_fatal("write_pid_file: fopen (\"%.100s\", \"w\") failed", |
362 |
|
|
pid_file); |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
void |
366 |
|
|
sanitise_stdfd(void) |
367 |
|
|
{ |
368 |
|
|
int nullfd, dupfd; |
369 |
|
|
|
370 |
|
|
if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
371 |
|
|
fprintf(stderr, "Couldn't open /dev/null: %s\n", |
372 |
|
|
strerror(errno)); |
373 |
|
|
exit(1); |
374 |
|
|
} |
375 |
|
|
while (++dupfd <= STDERR_FILENO) { |
376 |
|
|
/* Only populate closed fds */ |
377 |
|
|
if (fcntl(dupfd, F_GETFL) == -1 && errno == EBADF) { |
378 |
|
|
if (dup2(nullfd, dupfd) == -1) { |
379 |
|
|
fprintf(stderr, "dup2: %s\n", strerror(errno)); |
380 |
|
|
exit(1); |
381 |
|
|
} |
382 |
|
|
} |
383 |
|
|
} |
384 |
|
|
if (nullfd > STDERR_FILENO) |
385 |
|
|
close(nullfd); |
386 |
|
|
} |
387 |
|
|
|
388 |
|
|
int |
389 |
|
|
main(int argc, char *argv[]) |
390 |
|
|
{ |
391 |
|
|
fd_set *rfds, *wfds; |
392 |
|
|
int n, m; |
393 |
|
|
size_t mask_size; |
394 |
|
|
struct timeval tv, *timeout; |
395 |
|
|
|
396 |
|
|
closefrom(STDERR_FILENO + 1); |
397 |
|
|
|
398 |
|
|
/* |
399 |
|
|
* Make sure init() won't alloc fd 0, 1 or 2, as daemon() will close |
400 |
|
|
* them. |
401 |
|
|
*/ |
402 |
|
|
sanitise_stdfd(); |
403 |
|
|
|
404 |
|
|
/* Log cmd line parsing and initialization errors to stderr. */ |
405 |
|
|
log_to(stderr); |
406 |
|
|
parse_args(argc, argv); |
407 |
|
|
log_init(debug); |
408 |
|
|
log_print("isakmpd: starting"); |
409 |
|
|
|
410 |
|
|
/* Open protocols and services databases. */ |
411 |
|
|
setprotoent(1); |
412 |
|
|
setservent(1); |
413 |
|
|
|
414 |
|
|
/* Open command fifo */ |
415 |
|
|
ui_init(); |
416 |
|
|
|
417 |
|
|
set_slave_signals(); |
418 |
|
|
/* Daemonize before forking unpriv'ed child */ |
419 |
|
|
if (!debug) |
420 |
|
|
if (daemon(0, 0)) |
421 |
|
|
log_fatal("main: daemon (0, 0) failed"); |
422 |
|
|
|
423 |
|
|
/* Set timezone before priv'separation */ |
424 |
|
|
tzset(); |
425 |
|
|
|
426 |
|
|
write_pid_file(); |
427 |
|
|
|
428 |
|
|
if (monitor_init(debug)) { |
429 |
|
|
/* The parent, with privileges enters infinite monitor loop. */ |
430 |
|
|
monitor_loop(debug); |
431 |
|
|
exit(0); /* Never reached. */ |
432 |
|
|
} |
433 |
|
|
/* Child process only from this point on, no privileges left. */ |
434 |
|
|
|
435 |
|
|
init(); |
436 |
|
|
|
437 |
|
|
/* If we wanted IKE packet capture to file, initialize it now. */ |
438 |
|
|
if (pcap_file != 0) |
439 |
|
|
log_packet_init(pcap_file); |
440 |
|
|
|
441 |
|
|
/* Allocate the file descriptor sets just big enough. */ |
442 |
|
|
n = getdtablesize(); |
443 |
|
|
mask_size = howmany(n, NFDBITS) * sizeof(fd_mask); |
444 |
|
|
rfds = malloc(mask_size); |
445 |
|
|
if (!rfds) |
446 |
|
|
log_fatal("main: malloc (%lu) failed", |
447 |
|
|
(unsigned long)mask_size); |
448 |
|
|
wfds = malloc(mask_size); |
449 |
|
|
if (!wfds) |
450 |
|
|
log_fatal("main: malloc (%lu) failed", |
451 |
|
|
(unsigned long)mask_size); |
452 |
|
|
|
453 |
|
|
monitor_init_done(); |
454 |
|
|
|
455 |
|
|
while (1) { |
456 |
|
|
/* If someone has sent SIGHUP to us, reconfigure. */ |
457 |
|
|
if (sighupped) { |
458 |
|
|
sighupped = 0; |
459 |
|
|
log_print("SIGHUP received"); |
460 |
|
|
reinit(); |
461 |
|
|
} |
462 |
|
|
/* and if someone sent SIGUSR1, do a state report. */ |
463 |
|
|
if (sigusr1ed) { |
464 |
|
|
sigusr1ed = 0; |
465 |
|
|
log_print("SIGUSR1 received"); |
466 |
|
|
report(); |
467 |
|
|
} |
468 |
|
|
/* |
469 |
|
|
* and if someone set 'sigtermed' (SIGTERM, SIGINT or via the |
470 |
|
|
* UI), this indicates we should start a controlled shutdown |
471 |
|
|
* of the daemon. |
472 |
|
|
* |
473 |
|
|
* Note: Since _one_ message is sent per iteration of this |
474 |
|
|
* enclosing while-loop, and we want to send a number of |
475 |
|
|
* DELETE notifications, we must loop atleast this number of |
476 |
|
|
* times. The daemon_shutdown() function starts by queueing |
477 |
|
|
* the DELETEs, all other calls just increments the |
478 |
|
|
* 'sigtermed' variable until it reaches a "safe" value, and |
479 |
|
|
* the daemon exits. |
480 |
|
|
*/ |
481 |
|
|
if (sigtermed) |
482 |
|
|
daemon_shutdown(); |
483 |
|
|
|
484 |
|
|
/* Setup the descriptors to look for incoming messages at. */ |
485 |
|
|
bzero(rfds, mask_size); |
486 |
|
|
n = transport_fd_set(rfds); |
487 |
|
|
FD_SET(ui_socket, rfds); |
488 |
|
|
if (ui_socket + 1 > n) |
489 |
|
|
n = ui_socket + 1; |
490 |
|
|
|
491 |
|
|
/* |
492 |
|
|
* XXX Some day we might want to deal with an abstract |
493 |
|
|
* application class instead, with many instantiations |
494 |
|
|
* possible. |
495 |
|
|
*/ |
496 |
|
|
if (!app_none && app_socket >= 0) { |
497 |
|
|
FD_SET(app_socket, rfds); |
498 |
|
|
if (app_socket + 1 > n) |
499 |
|
|
n = app_socket + 1; |
500 |
|
|
} |
501 |
|
|
/* Setup the descriptors that have pending messages to send. */ |
502 |
|
|
bzero(wfds, mask_size); |
503 |
|
|
m = transport_pending_wfd_set(wfds); |
504 |
|
|
if (m > n) |
505 |
|
|
n = m; |
506 |
|
|
|
507 |
|
|
/* Find out when the next timed event is. */ |
508 |
|
|
timeout = &tv; |
509 |
|
|
timer_next_event(&timeout); |
510 |
|
|
|
511 |
|
|
n = select(n, rfds, wfds, 0, timeout); |
512 |
|
|
if (n == -1) { |
513 |
|
|
if (errno != EINTR) { |
514 |
|
|
log_error("main: select"); |
515 |
|
|
|
516 |
|
|
/* |
517 |
|
|
* In order to give the unexpected error |
518 |
|
|
* condition time to resolve without letting |
519 |
|
|
* this process eat up all available CPU |
520 |
|
|
* we sleep for a short while. |
521 |
|
|
*/ |
522 |
|
|
sleep(1); |
523 |
|
|
} |
524 |
|
|
} else if (n) { |
525 |
|
|
transport_handle_messages(rfds); |
526 |
|
|
transport_send_messages(wfds); |
527 |
|
|
if (FD_ISSET(ui_socket, rfds)) |
528 |
|
|
ui_handler(); |
529 |
|
|
if (!app_none && app_socket >= 0 && |
530 |
|
|
FD_ISSET(app_socket, rfds)) |
531 |
|
|
app_handler(); |
532 |
|
|
} |
533 |
|
|
timer_handle_expirations(); |
534 |
|
|
} |
535 |
|
|
} |