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