Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / atm / scspd / scspd.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
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.
12  *
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.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
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.2 2003/06/17 04:29:52 dillon Exp $
28  */
29
30
31 /*
32  * Server Cache Synchronization Protocol (SCSP) Support
33  * ----------------------------------------------------
34  *
35  * SCSP server daemon main line code
36  *
37  */
38
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>
52  
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <libatm.h>
56 #include <paths.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <syslog.h>
60 #include <unistd.h>
61
62 #include "scsp_msg.h"
63 #include "scsp_if.h"
64 #include "scsp_var.h"
65
66 /*
67  * Global variables
68  */
69 char            *prog;
70 char            *scsp_config_file = SCSPD_CONFIG;
71 FILE            *scsp_log_file = (FILE *)0;
72 int             scsp_log_syslog = 0;
73 Scsp_server     *scsp_server_head = (Scsp_server *)0;
74 Scsp_pending    *scsp_pending_head = (Scsp_pending *)0;
75 int             scsp_max_socket = -1;
76 int             scsp_debug_mode = 0;
77 int             scsp_trace_mode = 0;
78
79
80 /*
81  * Local variables
82  */
83 static int      scsp_hup_signal = 0;
84 static int      scsp_int_signal = 0;
85
86
87 /*
88  * SIGHUP signal handler
89  *
90  * Arguments:
91  *      sig     signal number
92  *
93  * Returns:
94  *      none
95  *
96  */
97 void
98 scsp_sighup(sig)
99         int     sig;
100 {
101         /*
102          * Flag the signal
103          */
104         scsp_hup_signal = 1;
105 }
106
107
108 /*
109  * SIGINT signal handler
110  *
111  * Arguments:
112  *      sig     signal number
113  *
114  * Returns:
115  *      none
116  *
117  */
118 void
119 scsp_sigint(sig)
120         int     sig;
121 {
122         /*
123          * Flag the signal
124          */
125         scsp_int_signal = 1;
126 }
127
128
129 /*
130  * Process command line parameters
131  *
132  * Arguments:
133  *      argc    number of command-line arguments
134  *      argv    list of pointers to command-line arguments
135  *
136  * Returns:
137  *      none
138  *
139  */
140 void
141 initialize(argc, argv)
142         int     argc;
143         char    **argv;
144 {
145         int     i;
146         char    *cp;
147
148         /*
149          * Save program name, ignoring any path components
150          */
151         if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
152                 prog++;
153         else
154                 prog = argv[0];
155
156         /*
157          * Make sure we're being invoked by the super user
158          */
159         i = getuid();
160         if (i != 0) {
161                 fprintf(stderr, "%s: You must be root to run this program\n",
162                                 prog);
163                 exit(1);
164         }
165
166         /*
167          * Check for command-line options
168          */
169         for (i = 1; i < argc; i++) {
170                 if (strcmp(argv[i], "-d") == 0) {
171                         /*
172                          * -d option -- set debug mode
173                          */
174                         scsp_debug_mode = 1;
175                 } else if (strcmp(argv[i], "-f") == 0) {
176                         /*
177                          * -f option -- set config file name
178                          */
179                         i++;
180                         if (i >= argc) {
181                                 fprintf(stderr, "%s: Configuration file name missing\n",
182                                                 prog);
183                                 exit(1);
184                         }
185                         scsp_config_file = argv[i];
186                 } else if (strncmp(argv[i], "-T", 2) == 0) {
187                         /*
188                          * -T option -- trace options
189                          */
190                         for (cp = &argv[i][2]; *cp; cp++) {
191                                 if (*cp == 'c')
192                                         scsp_trace_mode |= SCSP_TRACE_CAFSM;
193                                 else if (*cp == 'h')
194                                         scsp_trace_mode |= SCSP_TRACE_HFSM;
195                                 else if (*cp == 'i')
196                                         scsp_trace_mode |= SCSP_TRACE_CFSM;
197                                 else if (*cp == 'C')
198                                         scsp_trace_mode |= SCSP_TRACE_CA_MSG;
199                                 else if (*cp == 'H')
200                                         scsp_trace_mode |= SCSP_TRACE_HELLO_MSG;
201                                 else if (*cp == 'I')
202                                         scsp_trace_mode |= SCSP_TRACE_IF_MSG;
203                                 else
204                                         fprintf(stderr, "Invalid trace specification '%c' ignored\n",
205                                                         *cp);
206                         }
207                 } else {
208                         /*
209                          * Error -- unrecognized option
210                          */
211                         fprintf(stderr, "%s: Unrecognized option \"%s\"\n",
212                                         prog, argv[i]);
213                         exit(1);
214                 }
215         }
216 }
217
218
219 /*
220  * Daemon housekeeping
221  *
222  * Arguments:
223  *      None
224  *
225  * Returns:
226  *      None
227  *
228  */
229 static void
230 start_daemon()
231
232 {
233         int     dpid, fd, file_count, rc;
234
235         /*
236          * Ignore selected signals
237          */
238 #ifdef SIGTTOU
239         signal(SIGTTOU, SIG_IGN);
240 #endif
241 #ifdef SIGTTIN
242         signal(SIGTTIN, SIG_IGN);
243 #endif
244 #ifdef SIGTSTP
245         signal(SIGTSTP, SIG_IGN);
246 #endif
247 #ifdef SIGPIPE
248         signal(SIGPIPE, SIG_IGN);
249 #endif
250
251
252         /*
253          * Don't put the daemon into the background if
254          * we're in debug mode
255          */
256         if (scsp_debug_mode)
257                 goto daemon_bypass;
258
259         /*
260          * Put the daemon into the background
261          */
262         dpid = fork();
263         if (dpid < 0) {
264                 scsp_log(LOG_ERR, "fork failed");
265                 abort();
266         }
267         if (dpid > 0) {
268                 /*
269                  * This is the parent process--just exit and let
270                  * the daughter do all the work
271                  */
272                 exit(0);
273         }
274
275         /*
276          * Disassociate from any controlling terminal
277          */
278         rc = setpgrp(0, getpid());
279         if (rc <0) {
280                 scsp_log(LOG_ERR, "can't change process group");
281                 exit(1);
282         }
283         fd = open(_PATH_TTY, O_RDWR);
284         if (fd >= 0) {
285                 ioctl(fd, TIOCNOTTY, (char *)0);
286                 close(fd);
287         }
288
289         /*
290          * Close all open file descriptors
291          */
292         file_count = getdtablesize();
293         for (fd=0; fd<file_count; fd++) {
294                 close(fd);
295         }
296
297         /*
298          * Set up timers
299          */
300 daemon_bypass:
301         init_timer();
302
303         /*
304          * Move to a safe directory
305          */
306         chdir(SCSPD_DIR);
307
308         /*
309          * Clear the file mode creation mask
310          */
311         umask(0);
312
313
314         /*
315          * Set up signal handlers
316          */
317         rc = (int)signal(SIGHUP, scsp_sighup);
318         if (rc == -1) {
319                 scsp_log(LOG_ERR, "SIGHUP signal setup failed");
320                 exit(1);
321         }
322
323         rc = (int)signal(SIGINT, scsp_sigint);
324         if (rc == -1) {
325                 scsp_log(LOG_ERR, "SIGINT signal setup failed");
326                 exit(1);
327         }
328
329         /*
330          * Set up syslog for error logging
331          */
332         if (scsp_log_syslog || !scsp_log_file) {
333                 openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
334         }
335         scsp_log(LOG_INFO, "Starting SCSP daemon");
336 }
337
338
339 /*
340  * Main line code
341  *
342  * Process command line parameters, read configuration file, connect
343  * to configured clients, process data from DCSs.
344  *
345  * Arguments:
346  *      argc    number of command-line arguments
347  *      argv    list of pointers to command-line arguments
348  *
349  * Returns:
350  *      none
351  *
352  */
353 int
354 main(argc, argv)
355         int     argc;
356         char    *argv[];
357
358 {
359         int             i, rc, scsp_server_lsock;
360         Scsp_server     *ssp;
361         Scsp_dcs        *dcsp;
362         Scsp_pending    *next_psp, *psp;
363         fd_set          read_set, write_set, except_set;
364
365         /*
366          * Process command line arguments
367          */
368         initialize(argc, argv);
369
370         /*
371          * Put the daemon into the background
372          */
373         start_daemon();
374
375         /*
376          * Process configuration file
377          */
378         rc = scsp_config(scsp_config_file);
379         if (rc) {
380                 scsp_log(LOG_ERR, "Found %d error%s in configuration file",
381                                 rc, ((rc == 1) ? "" : "s"));
382                 exit(1);
383         }
384
385         /*
386          * Open the trace file if we need one
387          */
388         if (scsp_trace_mode) {
389                 scsp_open_trace();
390         }
391
392         /*
393          * Listen for connections from clients
394          */
395         scsp_server_lsock = scsp_server_listen();
396         if (scsp_server_lsock == -1) {
397                 scsp_log(LOG_ERR, "server listen failed");
398                 abort();
399         }
400
401         /*
402          * Main program loop -- we wait for:
403          *      a server listen to complete
404          *      a DCS listen to complete
405          *      a DCS connect to complete
406          *      data from a server
407          *      data from a DCS
408          */
409         while (1) {
410                 /*
411                  * Set up the file descriptor sets and select to wait
412                  * for input
413                  */
414                 FD_ZERO(&read_set);
415                 FD_ZERO(&write_set);
416                 FD_ZERO(&except_set);
417                 FD_SET(scsp_server_lsock, &read_set);
418                 for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
419                         if (ssp->ss_dcs_lsock != -1)
420                                 FD_SET(ssp->ss_dcs_lsock, &read_set);
421                         if (ssp->ss_sock != -1)
422                                 FD_SET(ssp->ss_sock, &read_set);
423                         for (dcsp = ssp->ss_dcs; dcsp;
424                                         dcsp = dcsp->sd_next) {
425                                 if (dcsp->sd_sock != -1) {
426                                         if (dcsp->sd_hello_state ==
427                                                         SCSP_HFSM_DOWN )
428                                                 FD_SET(dcsp->sd_sock,
429                                                         &write_set);
430                                         else
431                                                 FD_SET(dcsp->sd_sock,
432                                                         &read_set);
433                                 }
434                         }
435                 }
436                 for (psp = scsp_pending_head; psp; psp = psp->sp_next) {
437                         FD_SET(psp->sp_sock, &read_set);
438                 }
439                 rc = select(scsp_max_socket + 1, &read_set,
440                                 &write_set, &except_set,
441                                 (struct timeval *)0);
442                 if (rc < 0) {
443                         /*
444                          * Select error--check for possible signals
445                          */
446                         if (harp_timer_exec) {
447                                 /*
448                                  * Timer tick--process it
449                                  */
450                                 timer_proc();
451                                 continue;
452                         } else if (scsp_hup_signal) {
453                                 /*
454                                  * SIGHUP signal--reconfigure
455                                  */
456                                 scsp_hup_signal = 0;
457                                 scsp_reconfigure();
458                                 continue;
459                         } else if (scsp_int_signal) {
460                                 /*
461                                  * SIGINT signal--dump control blocks
462                                  */
463                                 print_scsp_dump();
464                                 scsp_int_signal = 0;
465                                 continue;
466                         } else if (errno == EINTR) {
467                                 /*
468                                  * EINTR--just ignore it
469                                  */
470                                 continue;
471                         } else {
472                                 /*
473                                  * Other error--this is a problem
474                                  */
475                                 scsp_log(LOG_ERR, "Select failed");
476                                 abort();
477                         }
478                 }
479
480                 /*
481                  * Check the read set for connections from servers
482                  */
483                 if (FD_ISSET(scsp_server_lsock, &read_set)) {
484                         FD_CLR(scsp_server_lsock, &read_set);
485                         rc = scsp_server_accept(scsp_server_lsock);
486                 }
487
488                 /*
489                  * Check the write set for new connections to DCSs
490                  */
491                 for (i = 0; i <= scsp_max_socket; i++) {
492                         if (FD_ISSET(i, &write_set)) {
493                                 FD_CLR(i, &write_set);
494                                 if ((dcsp = scsp_find_dcs(i)) != NULL) {
495                                         rc = scsp_hfsm(dcsp,
496                                                 SCSP_HFSM_VC_ESTAB,
497                                                 (Scsp_msg *)0);
498                                 }
499                         }
500                 }
501
502                 /*
503                  * Check the read set for connections from DCSs
504                  */
505                 for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) {
506                         if (ssp->ss_dcs_lsock != -1 &&
507                                         FD_ISSET(ssp->ss_dcs_lsock,
508                                                 &read_set)) {
509                                 FD_CLR(ssp->ss_dcs_lsock, &read_set);
510                                 dcsp = scsp_dcs_accept(ssp);
511                                 if (dcsp) {
512                                         rc = scsp_hfsm(dcsp,
513                                                 SCSP_HFSM_VC_ESTAB,
514                                                 (Scsp_msg *)0);
515                                 }
516                         }
517                 }
518
519                 /*
520                  * Check the read set for data from pending servers
521                  */
522                 for (psp = scsp_pending_head; psp; psp = next_psp) {
523                         next_psp = psp->sp_next;
524                         if (FD_ISSET(psp->sp_sock, &read_set)) {
525                                 FD_CLR(psp->sp_sock, &read_set);
526                                 rc = scsp_pending_read(psp);
527                         }
528                 }
529
530                 /*
531                  * Check the read set for data from servers or DCSs
532                  */
533                 for (i = 0; i <= scsp_max_socket; i++) {
534                         if (FD_ISSET(i, &read_set)) {
535                                 if ((ssp = scsp_find_server(i)) != NULL) {
536                                         rc = scsp_server_read(ssp);
537                                 } else if ((dcsp = scsp_find_dcs(i)) != NULL) {
538                                         rc = scsp_dcs_read(dcsp);
539                                 }
540                         }
541                 }
542         }
543 }