MFC: following 2 commits:
[dragonfly.git] / usr.sbin / atm / scspd / scspd.c
blob05bf80029c4a100678d831f89cde66434991ad95
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/usr.sbin/atm/scspd/scspd.c,v 1.3.2.1 2000/12/11 01:03:29 obrien Exp $
27 * @(#) $DragonFly: src/usr.sbin/atm/scspd/scspd.c,v 1.4 2007/11/25 01:28:23 swildner Exp $
32 * Server Cache Synchronization Protocol (SCSP) Support
33 * ----------------------------------------------------
35 * SCSP server daemon main line code
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/socket.h>
42 #include <sys/stat.h>
43 #include <sys/ttycom.h>
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <netatm/queue.h>
47 #include <netatm/atm.h>
48 #include <netatm/atm_if.h>
49 #include <netatm/atm_sap.h>
50 #include <netatm/atm_sys.h>
51 #include <netatm/atm_ioctl.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <libatm.h>
56 #include <paths.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <syslog.h>
61 #include <unistd.h>
63 #include "scsp_msg.h"
64 #include "scsp_if.h"
65 #include "scsp_var.h"
68 * Global variables
70 char *prog;
71 char *scsp_config_file = SCSPD_CONFIG;
72 FILE *scsp_log_file = (FILE *)0;
73 int scsp_log_syslog = 0;
74 Scsp_server *scsp_server_head = (Scsp_server *)0;
75 Scsp_pending *scsp_pending_head = (Scsp_pending *)0;
76 int scsp_max_socket = -1;
77 int scsp_debug_mode = 0;
78 int scsp_trace_mode = 0;
82 * Local variables
84 static int scsp_hup_signal = 0;
85 static int scsp_int_signal = 0;
89 * SIGHUP signal handler
91 * Arguments:
92 * sig signal number
94 * Returns:
95 * none
98 void
99 scsp_sighup(int sig)
102 * Flag the signal
104 scsp_hup_signal = 1;
109 * SIGINT signal handler
111 * Arguments:
112 * sig signal number
114 * Returns:
115 * none
118 void
119 scsp_sigint(int sig)
122 * Flag the signal
124 scsp_int_signal = 1;
129 * Process command line parameters
131 * Arguments:
132 * argc number of command-line arguments
133 * argv list of pointers to command-line arguments
135 * Returns:
136 * none
139 void
140 initialize(int argc, char **argv)
142 int i;
143 char *cp;
146 * Save program name, ignoring any path components
148 if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
149 prog++;
150 else
151 prog = argv[0];
154 * Make sure we're being invoked by the super user
156 i = getuid();
157 if (i != 0) {
158 fprintf(stderr, "%s: You must be root to run this program\n",
159 prog);
160 exit(1);
164 * Check for command-line options
166 for (i = 1; i < argc; i++) {
167 if (strcmp(argv[i], "-d") == 0) {
169 * -d option -- set debug mode
171 scsp_debug_mode = 1;
172 } else if (strcmp(argv[i], "-f") == 0) {
174 * -f option -- set config file name
176 i++;
177 if (i >= argc) {
178 fprintf(stderr, "%s: Configuration file name missing\n",
179 prog);
180 exit(1);
182 scsp_config_file = argv[i];
183 } else if (strncmp(argv[i], "-T", 2) == 0) {
185 * -T option -- trace options
187 for (cp = &argv[i][2]; *cp; cp++) {
188 if (*cp == 'c')
189 scsp_trace_mode |= SCSP_TRACE_CAFSM;
190 else if (*cp == 'h')
191 scsp_trace_mode |= SCSP_TRACE_HFSM;
192 else if (*cp == 'i')
193 scsp_trace_mode |= SCSP_TRACE_CFSM;
194 else if (*cp == 'C')
195 scsp_trace_mode |= SCSP_TRACE_CA_MSG;
196 else if (*cp == 'H')
197 scsp_trace_mode |= SCSP_TRACE_HELLO_MSG;
198 else if (*cp == 'I')
199 scsp_trace_mode |= SCSP_TRACE_IF_MSG;
200 else
201 fprintf(stderr, "Invalid trace specification '%c' ignored\n",
202 *cp);
204 } else {
206 * Error -- unrecognized option
208 fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
209 prog, argv[i]);
210 exit(1);
217 * Daemon housekeeping
219 * Arguments:
220 * None
222 * Returns:
223 * None
226 static void
227 start_daemon(void)
230 int dpid, fd, file_count, rc;
233 * Ignore selected signals
235 #ifdef SIGTTOU
236 signal(SIGTTOU, SIG_IGN);
237 #endif
238 #ifdef SIGTTIN
239 signal(SIGTTIN, SIG_IGN);
240 #endif
241 #ifdef SIGTSTP
242 signal(SIGTSTP, SIG_IGN);
243 #endif
244 #ifdef SIGPIPE
245 signal(SIGPIPE, SIG_IGN);
246 #endif
250 * Don't put the daemon into the background if
251 * we're in debug mode
253 if (scsp_debug_mode)
254 goto daemon_bypass;
257 * Put the daemon into the background
259 dpid = fork();
260 if (dpid < 0) {
261 scsp_log(LOG_ERR, "fork failed");
262 abort();
264 if (dpid > 0) {
266 * This is the parent process--just exit and let
267 * the daughter do all the work
269 exit(0);
273 * Disassociate from any controlling terminal
275 rc = setpgrp(0, getpid());
276 if (rc <0) {
277 scsp_log(LOG_ERR, "can't change process group");
278 exit(1);
280 fd = open(_PATH_TTY, O_RDWR);
281 if (fd >= 0) {
282 ioctl(fd, TIOCNOTTY, (char *)0);
283 close(fd);
287 * Close all open file descriptors
289 file_count = getdtablesize();
290 for (fd=0; fd<file_count; fd++) {
291 close(fd);
295 * Set up timers
297 daemon_bypass:
298 init_timer();
301 * Move to a safe directory
303 chdir(SCSPD_DIR);
306 * Clear the file mode creation mask
308 umask(0);
312 * Set up signal handlers
314 rc = (int)signal(SIGHUP, scsp_sighup);
315 if (rc == -1) {
316 scsp_log(LOG_ERR, "SIGHUP signal setup failed");
317 exit(1);
320 rc = (int)signal(SIGINT, scsp_sigint);
321 if (rc == -1) {
322 scsp_log(LOG_ERR, "SIGINT signal setup failed");
323 exit(1);
327 * Set up syslog for error logging
329 if (scsp_log_syslog || !scsp_log_file) {
330 openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
332 scsp_log(LOG_INFO, "Starting SCSP daemon");
337 * Main line code
339 * Process command line parameters, read configuration file, connect
340 * to configured clients, process data from DCSs.
342 * Arguments:
343 * argc number of command-line arguments
344 * argv list of pointers to command-line arguments
346 * Returns:
347 * none
351 main(int argc, char **argv)
353 int i, rc, scsp_server_lsock;
354 Scsp_server *ssp;
355 Scsp_dcs *dcsp;
356 Scsp_pending *next_psp, *psp;
357 fd_set read_set, write_set, except_set;
360 * Process command line arguments
362 initialize(argc, argv);
365 * Put the daemon into the background
367 start_daemon();
370 * Process configuration file
372 rc = scsp_config(scsp_config_file);
373 if (rc) {
374 scsp_log(LOG_ERR, "Found %d error%s in configuration file",
375 rc, ((rc == 1) ? "" : "s"));
376 exit(1);
380 * Open the trace file if we need one
382 if (scsp_trace_mode) {
383 scsp_open_trace();
387 * Listen for connections from clients
389 scsp_server_lsock = scsp_server_listen();
390 if (scsp_server_lsock == -1) {
391 scsp_log(LOG_ERR, "server listen failed");
392 abort();
396 * Main program loop -- we wait for:
397 * a server listen to complete
398 * a DCS listen to complete
399 * a DCS connect to complete
400 * data from a server
401 * data from a DCS
403 while (1) {
405 * Set up the file descriptor sets and select to wait
406 * for input
408 FD_ZERO(&read_set);
409 FD_ZERO(&write_set);
410 FD_ZERO(&except_set);
411 FD_SET(scsp_server_lsock, &read_set);
412 for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
413 if (ssp->ss_dcs_lsock != -1)
414 FD_SET(ssp->ss_dcs_lsock, &read_set);
415 if (ssp->ss_sock != -1)
416 FD_SET(ssp->ss_sock, &read_set);
417 for (dcsp = ssp->ss_dcs; dcsp;
418 dcsp = dcsp->sd_next) {
419 if (dcsp->sd_sock != -1) {
420 if (dcsp->sd_hello_state ==
421 SCSP_HFSM_DOWN )
422 FD_SET(dcsp->sd_sock,
423 &write_set);
424 else
425 FD_SET(dcsp->sd_sock,
426 &read_set);
430 for (psp = scsp_pending_head; psp; psp = psp->sp_next) {
431 FD_SET(psp->sp_sock, &read_set);
433 rc = select(scsp_max_socket + 1, &read_set,
434 &write_set, &except_set,
435 (struct timeval *)0);
436 if (rc < 0) {
438 * Select error--check for possible signals
440 if (harp_timer_exec) {
442 * Timer tick--process it
444 timer_proc();
445 continue;
446 } else if (scsp_hup_signal) {
448 * SIGHUP signal--reconfigure
450 scsp_hup_signal = 0;
451 scsp_reconfigure();
452 continue;
453 } else if (scsp_int_signal) {
455 * SIGINT signal--dump control blocks
457 print_scsp_dump();
458 scsp_int_signal = 0;
459 continue;
460 } else if (errno == EINTR) {
462 * EINTR--just ignore it
464 continue;
465 } else {
467 * Other error--this is a problem
469 scsp_log(LOG_ERR, "Select failed");
470 abort();
475 * Check the read set for connections from servers
477 if (FD_ISSET(scsp_server_lsock, &read_set)) {
478 FD_CLR(scsp_server_lsock, &read_set);
479 rc = scsp_server_accept(scsp_server_lsock);
483 * Check the write set for new connections to DCSs
485 for (i = 0; i <= scsp_max_socket; i++) {
486 if (FD_ISSET(i, &write_set)) {
487 FD_CLR(i, &write_set);
488 if ((dcsp = scsp_find_dcs(i)) != NULL) {
489 rc = scsp_hfsm(dcsp,
490 SCSP_HFSM_VC_ESTAB,
491 (Scsp_msg *)0);
497 * Check the read set for connections from DCSs
499 for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
500 if (ssp->ss_dcs_lsock != -1 &&
501 FD_ISSET(ssp->ss_dcs_lsock,
502 &read_set)) {
503 FD_CLR(ssp->ss_dcs_lsock, &read_set);
504 dcsp = scsp_dcs_accept(ssp);
505 if (dcsp) {
506 rc = scsp_hfsm(dcsp,
507 SCSP_HFSM_VC_ESTAB,
508 (Scsp_msg *)0);
514 * Check the read set for data from pending servers
516 for (psp = scsp_pending_head; psp; psp = next_psp) {
517 next_psp = psp->sp_next;
518 if (FD_ISSET(psp->sp_sock, &read_set)) {
519 FD_CLR(psp->sp_sock, &read_set);
520 rc = scsp_pending_read(psp);
525 * Check the read set for data from servers or DCSs
527 for (i = 0; i <= scsp_max_socket; i++) {
528 if (FD_ISSET(i, &read_set)) {
529 if ((ssp = scsp_find_server(i)) != NULL) {
530 rc = scsp_server_read(ssp);
531 } else if ((dcsp = scsp_find_dcs(i)) != NULL) {
532 rc = scsp_dcs_read(dcsp);