]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/main.c
58baffb0a05fd1884944dc4ecfc78b1a2f7d042a
[1ts-debian.git] / zephyr / server / main.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains the main loop of the Zephyr server
3  *
4  *      Created by:     John T. Kohl
5  *
6  *      $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/main.c,v $
7  *      $Author: zacheiss $
8  *
9  *      Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h". 
12  */
13
14 #include <zephyr/mit-copyright.h>
15 #include "zserver.h"
16 #include <sys/socket.h>
17 #include <sys/resource.h>
18
19 #ifndef lint
20 #ifndef SABER
21 static const char rcsid_main_c[] =
22     "$Id: main.c,v 1.69 2001/02/27 04:50:08 zacheiss Exp $";
23 #endif
24 #endif
25
26 /*
27  * Server loop for Zephyr.
28  */
29
30 /*
31   The Zephyr server maintains several linked lists of information.
32
33   There is an array of servers (otherservers) initialized and maintained
34   by server_s.c.
35
36   Each server descriptor contains a pointer to a linked list of hosts
37   which are ``owned'' by that server.  The first server is the ``limbo''
38   server which owns any host which was formerly owned by a dead server.
39
40   Each of these host list entries has an IP address and a pointer to a
41   linked list of clients on that host.
42
43   Each client has a sockaddr_in, a list of subscriptions, and possibly
44   a session key.
45
46   In addition, the class manager has copies of the pointers to the
47   clients which are registered with a particular class, the
48   not-yet-acknowledged list has copies of pointers to some clients,
49   and the hostm manager may have copies of pointers to some clients
50   (if the client has not acknowledged a packet after a given timeout).
51 */
52
53 #define EVER            (;;)            /* don't stop looping */
54
55 static int do_net_setup __P((void));
56 static int initialize __P((void));
57 static void usage __P((void));
58 static void do_reset __P((void));
59 static RETSIGTYPE bye __P((int));
60 static RETSIGTYPE dbug_on __P((int));
61 static RETSIGTYPE dbug_off __P((int));
62 static RETSIGTYPE sig_dump_db __P((int));
63 static RETSIGTYPE sig_dump_strings __P((int));
64 static RETSIGTYPE reset __P((int));
65 static RETSIGTYPE reap __P((int));
66 static void read_from_dump __P((char *dumpfile));
67 static void dump_db __P((void));
68 static void dump_strings __P((void));
69
70 #ifndef DEBUG
71 static void detach __P((void));
72 #endif
73
74 static short doreset = 0;               /* if it becomes 1, perform
75                                            reset functions */
76
77 int nfds;                               /* max file descriptor for select() */
78 int srv_socket;                         /* dgram socket for clients
79                                            and other servers */
80 int bdump_socket = -1;                  /* brain dump socket fd
81                                            (closed most of the time) */
82 fd_set interesting;                     /* the file descrips we are listening
83                                            to right now */
84 struct sockaddr_in srv_addr;            /* address of the socket */
85
86 Unacked *nacklist = NULL;               /* list of packets waiting for ack's */
87
88 unsigned short hm_port;                 /* host manager receiver port */
89 unsigned short hm_srv_port;             /* host manager server sending port */
90
91 char *programname;                      /* set to the basename of argv[0] */
92 char myname[MAXHOSTNAMELEN];            /* my host name */
93
94 char list_file[128];
95 #ifdef HAVE_KRB4
96 char srvtab_file[128];
97 char my_realm[REALM_SZ];
98 static char tkt_file[128];
99 #endif
100 char acl_dir[128];
101 char subs_file[128];
102
103 int zdebug;
104 #ifdef DEBUG_MALLOC
105 int dump_malloc_stats = 0;
106 unsigned long m_size;
107 #endif
108 #ifdef DEBUG
109 int zalone;
110 #endif
111
112 struct timeval t_local;                 /* store current time for other uses */
113
114 static int dump_db_flag = 0;
115 static int dump_strings_flag = 0;
116
117 u_long npackets;                        /* number of packets processed */
118 time_t uptime;                          /* when we started operations */
119 static int nofork;
120 struct in_addr my_addr;
121 char *bdump_version = "1.2";
122
123 int
124 main(argc, argv)
125     int argc;
126     char **argv;
127 {
128     int nfound;                 /* #fildes ready on select */
129     fd_set readable;
130     struct timeval tv;
131     int init_from_dump = 0;
132     char *dumpfile;
133 #ifdef _POSIX_VERSION
134     struct sigaction action;
135 #endif
136     int optchar;                        /* option processing */
137     extern char *optarg;
138     extern int optind;
139
140     sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, SERVER_LIST_FILE);
141 #ifdef HAVE_KRB4
142     sprintf(srvtab_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_SRVTAB);
143     sprintf(tkt_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_TKFILE);
144 #endif
145     sprintf(acl_dir, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_ACL_DIR);
146     sprintf(subs_file, "%s/zephyr/%s", SYSCONFDIR, DEFAULT_SUBS_FILE);
147
148     /* set name */
149     programname = strrchr(argv[0],'/');
150     programname = (programname) ? programname + 1 : argv[0];
151
152     /* process arguments */
153     while ((optchar = getopt(argc, argv, "dsnv:f:k:")) != EOF) {
154         switch(optchar) {
155           case 'd':
156             zdebug = 1;
157             break;
158 #ifdef DEBUG
159           case 's':
160             zalone = 1;
161             break;
162 #endif
163           case 'n':
164             nofork = 1;
165             break;
166           case 'k':
167 #ifdef HAVE_KRB4
168             strncpy(my_realm, optarg, REALM_SZ);
169 #endif
170             break;
171           case 'v':
172             bdump_version = optarg;
173             break;
174           case 'f':
175             init_from_dump = 0;
176             dumpfile = optarg;
177             break;
178           case '?':
179           default:
180             usage();
181             /*NOTREACHED*/
182         }
183     }
184
185 #ifdef HAVE_KRB4
186     /* if there is no readable srvtab and we are not standalone, there
187        is no possible way we can succeed, so we exit */
188
189     if (access(srvtab_file, R_OK)
190 #ifdef DEBUG            
191         && !zalone
192 #endif /* DEBUG */
193         ) {
194         fprintf(stderr, "NO ZEPHYR SRVTAB (%s) available; exiting\n",
195                 srvtab_file);
196         exit(1);
197     }
198     /* Use local realm if not specified on command line. */
199     if (!*my_realm) {
200         if (krb_get_lrealm(my_realm, 1) != KSUCCESS) {
201             fputs("Couldn't get local Kerberos realm; exiting.\n", stderr);
202             exit(1);
203         }
204     }
205 #endif /* HAVE_KRB4 */
206
207 #ifndef DEBUG
208     if (!nofork)
209         detach();
210 #endif /* DEBUG */
211
212     /* open log */
213     OPENLOG(programname, LOG_PID, LOG_LOCAL6);
214
215 #if defined (DEBUG) && 0
216     if (zalone)
217         syslog(LOG_DEBUG, "standalone operation");
218 #endif
219 #if 0
220     if (zdebug)
221         syslog(LOG_DEBUG, "debugging on");
222 #endif
223
224     /* set up sockets & my_addr and myname, 
225        find other servers and set up server table, initialize queues
226        for retransmits, initialize error tables,
227        set up restricted classes */
228
229     /* Initialize t_local for other uses */
230     gettimeofday(&t_local, NULL);
231
232     if (initialize())
233         exit(1);
234
235     if (init_from_dump)
236         read_from_dump(dumpfile);
237
238     /* Seed random number set.  */
239     srandom(getpid() ^ time(0));
240
241     /* chdir to somewhere where a core dump will survive */
242     if (chdir(TEMP_DIRECTORY) != 0)
243         syslog(LOG_ERR, "chdir failed (%m) (execution continuing)");
244
245     FD_ZERO(&interesting);
246     FD_SET(srv_socket, &interesting);
247
248     nfds = srv_socket + 1;
249
250
251 #ifdef _POSIX_VERSION
252     action.sa_flags = 0;
253     sigemptyset(&action.sa_mask);
254
255     action.sa_handler = bye;
256     sigaction(SIGINT, &action, NULL);
257     sigaction(SIGTERM, &action, NULL);
258
259     action.sa_handler = dbug_on;
260     sigaction(SIGUSR1, &action, NULL);
261
262     action.sa_handler = dbug_off;
263     sigaction(SIGUSR2, &action, NULL);
264
265     action.sa_handler = reap;
266     sigaction(SIGCHLD, &action, NULL);
267
268     action.sa_handler = sig_dump_db;
269     sigaction(SIGFPE, &action, NULL);
270
271 #ifdef SIGEMT
272     action.sa_handler = sig_dump_strings;
273     sigaction(SIGEMT, &action, NULL);
274 #endif
275
276     action.sa_handler = reset;
277     sigaction(SIGHUP, &action, NULL);
278 #else /* !posix */
279     signal(SIGINT, bye);
280     signal(SIGTERM, bye);
281     signal(SIGUSR1, dbug_on);
282     signal(SIGUSR2, dbug_off);
283     signal(SIGCHLD, reap);
284     signal(SIGFPE, sig_dump_db);
285 #ifdef SIGEMT
286     signal(SIGEMT, sig_dump_strings);
287 #endif
288     signal(SIGHUP, reset);
289 #endif /* _POSIX_VERSION */
290
291     syslog(LOG_NOTICE, "Ready for action");
292
293     /* Reinitialize t_local now that initialization is done. */
294     gettimeofday(&t_local, NULL);
295     uptime = NOW;
296 #ifdef HAVE_KRB4
297     timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL);
298 #endif
299
300     realm_wakeup();
301 #ifdef DEBUG_MALLOC
302     malloc_inuse(&m_size);
303 #endif
304     for EVER {
305         if (doreset)
306             do_reset();
307
308         if (dump_db_flag)
309             dump_db();
310         if (dump_strings_flag)
311             dump_strings();
312
313         timer_process();
314
315         readable = interesting;
316         if (msgs_queued()) {
317             /* when there is input in the queue, we
318                artificially set up to pick up the input */
319             nfound = 1;
320             FD_ZERO(&readable);
321         } else  {
322             nfound = select(nfds, &readable, NULL, NULL, timer_timeout(&tv));
323         }
324
325         /* Initialize t_local for other uses */
326         gettimeofday(&t_local, (struct timezone *)0);
327                 
328         /* don't flame about EINTR, since a SIGUSR1 or SIGUSR2
329            can generate it by interrupting the select */
330         if (nfound < 0) {
331             if (errno != EINTR)
332                 syslog(LOG_WARNING, "select error: %m");
333 #ifdef DEBUG_MALLOC
334             if (dump_malloc_stats) {
335                 unsigned long foo,histid2;
336
337                 dump_malloc_stats = 0;
338                 foo = malloc_inuse(&histid2);
339                 printf("Total inuse: %d\n",foo);
340                 malloc_list(2,m_size,histid2);
341             }
342 #endif
343             continue;
344         }
345
346         if (nfound == 0) {
347             /* either we timed out or we were just
348                polling for input.  Either way we want to continue
349                the loop, and process the next timeout */
350             continue;
351         } else {
352             if (bdump_socket >= 0 && FD_ISSET(bdump_socket,&readable))
353                 bdump_send();
354             else if (msgs_queued() || FD_ISSET(srv_socket, &readable))
355                 handle_packet();
356             else
357                 syslog(LOG_ERR, "select weird?!?!");
358         }
359     }
360 }
361
362 /* Initialize net stuff.
363    Set up the server array.
364    Initialize the packet ack queues to be empty.
365    Initialize the error tables.
366    Restrict certain classes.
367    */
368
369 static int
370 initialize()
371 {
372     if (do_net_setup())
373         return(1);
374
375     server_init();
376
377 #ifdef HAVE_KRB4
378     krb_set_tkt_string(tkt_file);
379 #endif
380     realm_init();
381     
382     ZSetServerState(1);
383     ZInitialize();              /* set up the library */
384 #ifdef HAVE_KRB4
385     /* Override what Zinitialize set for ZGetRealm() */
386     if (*my_realm) 
387       strcpy(__Zephyr_realm, my_realm);
388 #endif
389     init_zsrv_err_tbl();        /* set up err table */
390
391     ZSetFD(srv_socket);         /* set up the socket as the input fildes */
392
393     /* set up default strings */
394
395     class_control = make_string(ZEPHYR_CTL_CLASS, 1);
396     class_admin = make_string(ZEPHYR_ADMIN_CLASS, 1);
397     class_hm = make_string(HM_CTL_CLASS, 1);
398     class_ulogin = make_string(LOGIN_CLASS, 1);
399     class_ulocate = make_string(LOCATE_CLASS, 1);
400     wildcard_instance = make_string(WILDCARD_INSTANCE, 1);
401     empty = make_string("", 0);
402
403     /* restrict certain classes */
404     access_init();
405     return 0;
406 }
407
408 /* 
409  * Set up the server and client sockets, and initialize my_addr and myname
410  */
411
412 static int
413 do_net_setup()
414 {
415     struct servent *sp;
416     struct hostent *hp;
417     char hostname[MAXHOSTNAMELEN+1];
418     int flags;
419
420     if (gethostname(hostname, MAXHOSTNAMELEN + 1)) {
421         syslog(LOG_ERR, "no hostname: %m");
422         return 1;
423     }
424     hp = gethostbyname(hostname);
425     if (!hp) {
426         syslog(LOG_ERR, "no gethostbyname repsonse");
427         strncpy(myname, hostname, MAXHOSTNAMELEN);
428         return 1;
429     }
430     strncpy(myname, hp->h_name, MAXHOSTNAMELEN);
431     memcpy(&my_addr, hp->h_addr, sizeof(hp->h_addr));
432
433     setservent(1);              /* keep file/connection open */
434
435     memset(&srv_addr, 0, sizeof(srv_addr));
436     srv_addr.sin_family = AF_INET;
437     sp = getservbyname(SERVER_SVCNAME, "udp");
438     srv_addr.sin_port = (sp) ? sp->s_port : SERVER_SVC_FALLBACK;
439
440     sp = getservbyname(HM_SVCNAME, "udp");
441     hm_port = (sp) ? sp->s_port : HM_SVC_FALLBACK;
442         
443     sp = getservbyname(HM_SRV_SVCNAME, "udp");
444     hm_srv_port = (sp) ? sp->s_port : HM_SRV_SVC_FALLBACK;
445         
446     srv_socket = socket(AF_INET, SOCK_DGRAM, 0);
447     if (srv_socket < 0) {
448         syslog(LOG_ERR, "client_sock failed: %m");
449         return 1;
450     }
451     if (bind(srv_socket, (struct sockaddr *) &srv_addr,
452              sizeof(srv_addr)) < 0) {
453         syslog(LOG_ERR, "client bind failed: %m");
454         return 1;
455     }
456
457     /* set not-blocking */
458 #ifdef _POSIX_VERSION
459     flags = fcntl(srv_socket, F_GETFL);
460     flags |= O_NONBLOCK;
461     fcntl(srv_socket, F_SETFL, flags);
462 #else
463     flags = 1;
464     ioctl(srv_socket, FIONBIO, &flags);
465 #endif
466
467     return 0;
468 }    
469
470
471 /*
472  * print out a usage message.
473  */
474
475 static void
476 usage()
477 {
478 #ifdef DEBUG
479         fprintf(stderr, "Usage: %s [-d] [-s] [-n] [-k realm] [-f dumpfile]\n",
480                 programname);
481 #else
482         fprintf(stderr, "Usage: %s [-d] [-n] [-k realm] [-f dumpfile]\n",
483                 programname);
484 #endif /* DEBUG */
485         exit(2);
486 }
487
488 int
489 packets_waiting()
490 {
491     fd_set readable, initial;
492     struct timeval tv;
493
494     if (msgs_queued())
495         return 1;
496     FD_ZERO(&initial);
497     FD_SET(srv_socket, &initial);
498     readable = initial;
499     tv.tv_sec = tv.tv_usec = 0;
500     return (select(srv_socket + 1, &readable, NULL, NULL, &tv) > 0);
501 }
502
503 static RETSIGTYPE
504 bye(sig)
505     int sig;
506 {
507     server_shutdown();          /* tell other servers */
508 #ifdef REALM_MGMT
509     realm_shutdown();           /* tell other realms */
510 #endif
511     hostm_shutdown();           /* tell our hosts */
512     kill_realm_pids();
513 #ifdef HAVE_KRB4
514     dest_tkt();
515 #endif
516     syslog(LOG_NOTICE, "goodbye (sig %d)", sig);
517     exit(0);
518 }
519
520 static RETSIGTYPE
521 dbug_on(sig)
522     int sig;
523 {
524     syslog(LOG_DEBUG, "debugging turned on");
525 #ifdef DEBUG_MALLOC
526     dump_malloc_stats = 1;
527 #endif
528     zdebug = 1;
529 }
530
531 static RETSIGTYPE
532 dbug_off(sig)
533     int sig;
534 {
535     syslog(LOG_DEBUG, "debugging turned off");
536 #ifdef DEBUG_MALLOC
537     malloc_inuse(&m_size);
538 #endif
539     zdebug = 0;
540 }
541
542 int fork_for_dump = 0;
543
544 static RETSIGTYPE
545 sig_dump_strings(sig)
546     int sig;
547 {
548     dump_strings_flag = 1;
549 }
550
551 static void dump_strings()
552 {
553     char filename[128];
554
555     FILE *fp;
556     int oerrno = errno;
557
558     sprintf(filename, "%szephyr.strings", TEMP_DIRECTORY);
559     fp = fopen (filename, "w");
560     if (!fp) {
561         syslog(LOG_ERR, "can't open strings dump file: %m");
562         errno = oerrno;
563         dump_strings_flag = 0;
564         return;
565     }
566     syslog(LOG_INFO, "dumping strings to disk");
567     print_string_table(fp);
568     if (fclose(fp) == EOF)
569         syslog(LOG_ERR, "error writing strings dump file");
570     else
571         syslog(LOG_INFO, "dump done");
572     oerrno = errno;
573     dump_strings_flag = 0;
574     return;
575 }
576
577 static RETSIGTYPE
578 sig_dump_db(sig)
579     int sig;
580 {
581     dump_db_flag = 1;
582 }
583
584 static void dump_db()
585 {
586     /* dump the in-core database to human-readable form on disk */
587     FILE *fp;
588     int oerrno = errno;
589     int pid;
590     char filename[128];
591
592     pid = (fork_for_dump) ? fork() : -1;
593     if (pid > 0) {
594         dump_db_flag = 0;
595         return;
596     }
597     sprintf(filename, "%szephyr.db", TEMP_DIRECTORY);
598     fp = fopen(filename, "w");
599     if (!fp) {
600         syslog(LOG_ERR, "can't open dump database");
601         errno = oerrno;
602         dump_db_flag = 0;
603         return;
604     }
605     syslog(LOG_INFO, "dumping to disk");
606     server_dump_servers(fp);
607     uloc_dump_locs(fp);
608     client_dump_clients(fp);
609     triplet_dump_subs(fp);
610     realm_dump_realms(fp);
611     syslog(LOG_INFO, "dump done");
612     if (fclose(fp) == EOF)
613         syslog(LOG_ERR, "can't close dump db");
614     if (pid == 0)
615         exit(0);
616     errno = oerrno;
617     dump_db_flag = 0;
618 }
619
620 static RETSIGTYPE
621 reset(sig)
622     int sig;
623 {
624 #if 1
625     zdbug((LOG_DEBUG,"reset()"));
626 #endif
627     doreset = 1;
628 }
629
630 static RETSIGTYPE
631 reap(sig)
632     int sig;
633 {
634     int pid, i = 0;
635     int oerrno = errno;
636     Realm *rlm;
637 #ifdef _POSIX_VERSION
638     int waitb;
639 #else
640     union wait waitb;
641 #endif
642 #if 1
643     zdbug((LOG_DEBUG,"reap()"));
644 #endif
645 #ifdef _POSIX_VERSION
646     while ((pid = waitpid(-1, &waitb, WNOHANG)) == 0) 
647       { i++; if (i > 10) break; }
648 #else
649     while ((pid = wait3 (&waitb, WNOHANG, (struct rusage*) 0)) == 0) 
650       { i++; if (i > 10) break; }
651 #endif
652
653     errno = oerrno;
654  
655     if (pid) {
656       if (WIFSIGNALED(waitb) == 0) {
657         if (WIFEXITED(waitb) != 0) {
658           rlm = realm_get_realm_by_pid(pid);
659           if (rlm) {
660             rlm->child_pid = 0;
661             rlm->have_tkt = 1;
662           }
663         }
664       } else {
665         rlm = realm_get_realm_by_pid(pid);
666         if (rlm) {
667           rlm->child_pid = 0;
668         }
669       }
670     }
671 }
672
673 static void
674 do_reset()
675 {
676     int oerrno = errno;
677 #ifdef _POSIX_VERSION
678     sigset_t mask, omask;
679 #else
680     int omask;
681 #endif
682 #if 0
683     zdbug((LOG_DEBUG,"do_reset()"));
684 #endif
685 #ifdef _POSIX_VERSION
686     sigemptyset(&mask);
687     sigaddset(&mask, SIGHUP);
688     sigprocmask(SIG_BLOCK, &mask, &omask);
689 #else
690     omask = sigblock(sigmask(SIGHUP));
691 #endif
692
693     /* reset various things in the server's state */
694     subscr_reset();
695     server_reset();
696     access_reinit();
697     syslog(LOG_INFO, "restart completed");
698     doreset = 0;
699     errno = oerrno;
700 #ifdef _POSIX_VERSION
701     sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0);
702 #else
703     sigsetmask(omask);
704 #endif
705 }
706
707 #ifndef DEBUG
708 /*
709  * detach from the terminal
710  */
711
712 static void
713 detach()
714 {
715     /* detach from terminal and fork. */
716     int i;
717     long size;
718
719 #ifdef _POSIX_VERSION
720     size = sysconf(_SC_OPEN_MAX);
721 #else
722     size = getdtablesize();
723 #endif
724     /* profiling seems to get confused by fork() */
725     i = fork ();
726     if (i) {
727         if (i < 0)
728             perror("fork");
729         exit(0);
730     }
731
732     for (i = 0; i < size; i++)
733         close(i);
734
735     i = open("/dev/tty", O_RDWR, 666);
736 #ifdef TIOCNOTTY /* Only necessary on old systems. */
737     ioctl(i, TIOCNOTTY, NULL);
738 #endif
739     close(i);
740 #ifdef _POSIX_VERSION
741     setsid();
742 #endif
743 }
744 #endif /* not DEBUG */
745
746 static void
747 read_from_dump(dumpfile)
748     char *dumpfile;
749 {
750     /* Not yet implemented. */
751     return;
752 }
753