Add some #include's to fix 'implicit declaration of...' warnings.
[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 = (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;
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, (char *)0);
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         rc = (int)signal(SIGHUP, scsp_sighup);
315         if (rc == -1) {
316                 scsp_log(LOG_ERR, "SIGHUP signal setup failed");
317                 exit(1);
318         }
319
320         rc = (int)signal(SIGINT, scsp_sigint);
321         if (rc == -1) {
322                 scsp_log(LOG_ERR, "SIGINT signal setup failed");
323                 exit(1);
324         }
325
326         /*
327          * Set up syslog for error logging
328          */
329         if (scsp_log_syslog || !scsp_log_file) {
330                 openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON);
331         }
332         scsp_log(LOG_INFO, "Starting SCSP daemon");
333 }
334
335
336 /*
337  * Main line code
338  *
339  * Process command line parameters, read configuration file, connect
340  * to configured clients, process data from DCSs.
341  *
342  * Arguments:
343  *      argc    number of command-line arguments
344  *      argv    list of pointers to command-line arguments
345  *
346  * Returns:
347  *      none
348  *
349  */
350 int
351 main(int argc, char **argv)
352 {
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;
358
359         /*
360          * Process command line arguments
361          */
362         initialize(argc, argv);
363
364         /*
365          * Put the daemon into the background
366          */
367         start_daemon();
368
369         /*
370          * Process configuration file
371          */
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);
377         }
378
379         /*
380          * Open the trace file if we need one
381          */
382         if (scsp_trace_mode) {
383                 scsp_open_trace();
384         }
385
386         /*
387          * Listen for connections from clients
388          */
389         scsp_server_lsock = scsp_server_listen();
390         if (scsp_server_lsock == -1) {
391                 scsp_log(LOG_ERR, "server listen failed");
392                 abort();
393         }
394
395         /*
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
402          */
403         while (1) {
404                 /*
405                  * Set up the file descriptor sets and select to wait
406                  * for input
407                  */
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);
427                                 }
428                         }
429                 }
430                 for (psp = scsp_pending_head; psp; psp = psp->sp_next) {
431                         FD_SET(psp->sp_sock, &read_set);
432                 }
433                 rc = select(scsp_max_socket + 1, &read_set,
434                                 &write_set, &except_set,
435                                 (struct timeval *)0);
436                 if (rc < 0) {
437                         /*
438                          * Select error--check for possible signals
439                          */
440                         if (harp_timer_exec) {
441                                 /*
442                                  * Timer tick--process it
443                                  */
444                                 timer_proc();
445                                 continue;
446                         } else if (scsp_hup_signal) {
447                                 /*
448                                  * SIGHUP signal--reconfigure
449                                  */
450                                 scsp_hup_signal = 0;
451                                 scsp_reconfigure();
452                                 continue;
453                         } else if (scsp_int_signal) {
454                                 /*
455                                  * SIGINT signal--dump control blocks
456                                  */
457                                 print_scsp_dump();
458                                 scsp_int_signal = 0;
459                                 continue;
460                         } else if (errno == EINTR) {
461                                 /*
462                                  * EINTR--just ignore it
463                                  */
464                                 continue;
465                         } else {
466                                 /*
467                                  * Other error--this is a problem
468                                  */
469                                 scsp_log(LOG_ERR, "Select failed");
470                                 abort();
471                         }
472                 }
473
474                 /*
475                  * Check the read set for connections from servers
476                  */
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);
480                 }
481
482                 /*
483                  * Check the write set for new connections to DCSs
484                  */
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);
492                                 }
493                         }
494                 }
495
496                 /*
497                  * Check the read set for connections from DCSs
498                  */
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);
509                                 }
510                         }
511                 }
512
513                 /*
514                  * Check the read set for data from pending servers
515                  */
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);
521                         }
522                 }
523
524                 /*
525                  * Check the read set for data from servers or DCSs
526                  */
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);
533                                 }
534                         }
535                 }
536         }
537 }