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