BSD 4_3_Reno release
[unix-history] / usr / src / usr.sbin / timed / timed / slave.c
index 81b7fea..1ed85b4 100644 (file)
@@ -1,30 +1,45 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)slave.c    2.1 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)slave.c    2.21 (Berkeley) 6/1/90";
+#endif /* not lint */
 
 #include "globals.h"
 #include <protocols/timed.h>
 #include <setjmp.h>
 
 #include "globals.h"
 #include <protocols/timed.h>
 #include <setjmp.h>
+#include "pathnames.h"
 
 extern jmp_buf jmpenv;
 
 
 extern jmp_buf jmpenv;
 
+extern u_short sequence;
+
 slave()
 {
        int length;
        int senddateack;
 slave()
 {
        int length;
        int senddateack;
-       long electiontime, refusetime;
+       long electiontime, refusetime, looktime;
        u_short seq;
        char candidate[MAXHOSTNAMELEN];
        u_short seq;
        char candidate[MAXHOSTNAMELEN];
-       struct tsp *msg, *readmsg();
+       struct tsp *msg, to, *readmsg();
        struct sockaddr_in saveaddr, msaveaddr;
        struct sockaddr_in saveaddr, msaveaddr;
-       struct timeval wait;
-       struct timeval time;
+       struct timeval time, wait;
        struct tsp *answer, *acksend();
        int timeout();
        char *date();
        struct tsp *answer, *acksend();
        int timeout();
        char *date();
@@ -33,24 +48,42 @@ slave()
        char olddate[32];
        struct sockaddr_in server;
        register struct netinfo *ntp;
        char olddate[32];
        struct sockaddr_in server;
        register struct netinfo *ntp;
+       int ind;
+       struct tsp resp;
+       extern int Mflag;
+       extern int justquit;
 #ifdef MEASURE
        extern FILE *fp;
 #endif
 #ifdef MEASURE
        extern FILE *fp;
 #endif
+       if (slavenet) {
+               resp.tsp_type = TSP_SLAVEUP;
+               resp.tsp_vers = TSPVERSION;
+               (void)strcpy(resp.tsp_name, hostname);
+               bytenetorder(&resp);
+               if (sendto(sock, (char *)&resp, sizeof(struct tsp), 0,
+                   &slavenet->dest_addr, sizeof(struct sockaddr_in)) < 0) {
+                       syslog(LOG_ERR, "sendto: %m");
+                       exit(1);
+               }
+       }
 
        if (status & MASTER) {
 #ifdef MEASURE
 
        if (status & MASTER) {
 #ifdef MEASURE
-               fp = fopen("/usr/adm/timed.masterlog", "w");
-               setlinebuf(fp);
+               if (fp == NULL) {
+                       fp = fopen(_PATH_MASTERLOG, "w");
+                       setlinebuf(fp);
+               }
 #endif
 #endif
-               syslog(LOG_NOTICE, "THIS MACHINE IS A SUBMASTER");
+               syslog(LOG_INFO, "THIS MACHINE IS A SUBMASTER");
                if (trace) {
                        fprintf(fd, "THIS MACHINE IS A SUBMASTER\n");
                }
                for (ntp = nettab; ntp != NULL; ntp = ntp->next)
                        if (ntp->status == MASTER)
                                masterup(ntp);
                if (trace) {
                        fprintf(fd, "THIS MACHINE IS A SUBMASTER\n");
                }
                for (ntp = nettab; ntp != NULL; ntp = ntp->next)
                        if (ntp->status == MASTER)
                                masterup(ntp);
+
        } else {
        } else {
-               syslog(LOG_NOTICE, "THIS MACHINE IS A SLAVE");
+               syslog(LOG_INFO, "THIS MACHINE IS A SLAVE");
                if (trace) {
                        fprintf(fd, "THIS MACHINE IS A SLAVE\n");
                }
                if (trace) {
                        fprintf(fd, "THIS MACHINE IS A SLAVE\n");
                }
@@ -62,6 +95,13 @@ slave()
 
        (void)gettimeofday(&time, (struct timezone *)0);
        electiontime = time.tv_sec + delay2;
 
        (void)gettimeofday(&time, (struct timezone *)0);
        electiontime = time.tv_sec + delay2;
+       if (Mflag)
+               if (justquit)
+                       looktime = time.tv_sec + delay2;
+               else 
+                       looktime = 1;
+       else
+               looktime = 0;
 
 loop:
        length = sizeof(struct sockaddr_in);
 
 loop:
        length = sizeof(struct sockaddr_in);
@@ -71,13 +111,89 @@ loop:
                        fprintf(fd, "election timer expired\n");
                longjmp(jmpenv, 1);
        }
                        fprintf(fd, "election timer expired\n");
                longjmp(jmpenv, 1);
        }
+       if (looktime && time.tv_sec > looktime) {
+               if (trace) 
+                       fprintf(fd, "Looking for nets to master and loops\n");
+               
+               if (nignorednets > 0) {
+                       for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+                               if (ntp->status == IGNORE) {
+                                       lookformaster(ntp);
+                                       if (ntp->status == MASTER)
+                                               masterup(ntp);
+                                       else
+                                               ntp->status = IGNORE;
+                               }
+                       }
+                       setstatus();
+#ifdef MEASURE
+                       /*
+                        * Check to see if we just became master
+                        * (file not open)
+                        */
+                       if (fp == NULL) {
+                               fp = fopen(_PATH_MASTERLOG, "w");
+                               setlinebuf(fp);
+                       }
+#endif
+               }
+
+               for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+                   if (ntp->status == MASTER) {
+                       to.tsp_type = TSP_LOOP;
+                       to.tsp_vers = TSPVERSION;
+                       to.tsp_seq = sequence++;
+                       to.tsp_hopcnt = 10;
+                       (void)strcpy(to.tsp_name, hostname);
+                       bytenetorder(&to);
+                       if (sendto(sock, (char *)&to, sizeof(struct tsp), 0,
+                           &ntp->dest_addr, sizeof(struct sockaddr_in)) < 0) {
+                               syslog(LOG_ERR, "sendto: %m");
+                               exit(1);
+                       }
+                   }
+               }
+               (void)gettimeofday(&time, (struct timezone *)0);
+               looktime = time.tv_sec + delay2;
+       }
        wait.tv_sec = electiontime - time.tv_sec + 10;
        wait.tv_usec = 0;
        msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
        if (msg != NULL) {
        wait.tv_sec = electiontime - time.tv_sec + 10;
        wait.tv_usec = 0;
        msg = readmsg(TSP_ANY, (char *)ANYADDR, &wait, (struct netinfo *)NULL);
        if (msg != NULL) {
+               switch (msg->tsp_type) {
+               case TSP_SETDATE:
+#ifdef TESTING
+               case TSP_TEST:
+#endif
+               case TSP_MSITE:
+               case TSP_TRACEOFF:
+               case TSP_TRACEON:
+                       break;
+               case TSP_MASTERUP:
+                       if (fromnet == NULL) {
+                               if (trace) {
+                                       fprintf(fd, "slave ignored: ");
+                                       print(msg, &from);
+                               }
+                               goto loop;
+                       }
+                       break;
+               default:
+                       if (fromnet == NULL || fromnet->status == IGNORE) {
+                               if (trace) {
+                                       fprintf(fd, "slave ignored: ");
+                                       print(msg, &from);
+                               }
+                               goto loop;
+                       }
+                       break;
+               }
+
                switch (msg->tsp_type) {
 
                case TSP_ADJTIME:
                switch (msg->tsp_type) {
 
                case TSP_ADJTIME:
+                       if (fromnet->status != SLAVE)
+                               break;
                        (void)gettimeofday(&time, (struct timezone *)0);
                        electiontime = time.tv_sec + delay2;
                        if (seq != msg->tsp_seq) {
                        (void)gettimeofday(&time, (struct timezone *)0);
                        electiontime = time.tv_sec + delay2;
                        if (seq != msg->tsp_seq) {
@@ -91,18 +207,23 @@ loop:
                        }
                        break;
                case TSP_SETTIME:
                        }
                        break;
                case TSP_SETTIME:
+                       if (fromnet->status != SLAVE)
+                               break;
                        if (seq == msg->tsp_seq)
                                break;
 
                        seq = msg->tsp_seq;
 
                        (void)strcpy(olddate, date());
                        if (seq == msg->tsp_seq)
                                break;
 
                        seq = msg->tsp_seq;
 
                        (void)strcpy(olddate, date());
+                       logwtmp("|", "date", "");
                        (void)settimeofday(&msg->tsp_time,
                                (struct timezone *)0);
                        (void)settimeofday(&msg->tsp_time,
                                (struct timezone *)0);
+                       logwtmp("{", "date", "");
                        syslog(LOG_NOTICE, "date changed by %s from: %s",
                                msg->tsp_name, olddate);
                        if ((status & SUBMASTER) == SUBMASTER)
                                spreadtime();
                        syslog(LOG_NOTICE, "date changed by %s from: %s",
                                msg->tsp_name, olddate);
                        if ((status & SUBMASTER) == SUBMASTER)
                                spreadtime();
+                       (void)gettimeofday(&time, (struct timezone *)0);
                        electiontime = time.tv_sec + delay2;
 
                        if (senddateack == ON) {
                        electiontime = time.tv_sec + delay2;
 
                        if (senddateack == ON) {
@@ -120,6 +241,10 @@ loop:
                        }
                        break;
                case TSP_MASTERUP:
                        }
                        break;
                case TSP_MASTERUP:
+                       if (slavenet && fromnet != slavenet)
+                               break;
+                       makeslave(fromnet);
+                       setstatus();
                        msg->tsp_type = TSP_SLAVEUP;
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
                        msg->tsp_type = TSP_SLAVEUP;
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
@@ -138,19 +263,22 @@ loop:
                        refusetime = 0;
                        break;
                case TSP_MASTERREQ:
                        refusetime = 0;
                        break;
                case TSP_MASTERREQ:
+                       if (fromnet->status != SLAVE)
+                               break;
                        (void)gettimeofday(&time, (struct timezone *)0);
                        electiontime = time.tv_sec + delay2;
                        break;
                        (void)gettimeofday(&time, (struct timezone *)0);
                        electiontime = time.tv_sec + delay2;
                        break;
-               case TSP_DATE:
+               case TSP_SETDATE:
                        saveaddr = from;
                        saveaddr = from;
-                       msg->tsp_time.tv_usec = 0;
-                       msg->tsp_type = TSP_DATEREQ;
+                       msg->tsp_type = TSP_SETDATEREQ;
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
                        for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
                                if (ntp->status == SLAVE)
                                        break;
                        }
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
                        for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
                                if (ntp->status == SLAVE)
                                        break;
                        }
+                       if (ntp == NULL)
+                               break;
                        answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
                            TSP_DATEACK, ntp);
                        if (answer != NULL) {
                        answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
                            TSP_DATEACK, ntp);
                        if (answer != NULL) {
@@ -166,13 +294,24 @@ loop:
                                senddateack = ON;
                        }
                        break;
                                senddateack = ON;
                        }
                        break;
-               case TSP_DATEREQ:
-                       if (status != SUBMASTER)
+               case TSP_SETDATEREQ:
+                       saveaddr = from;
+                       if (status != SUBMASTER || fromnet->status != MASTER)
                                break;
                        for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
                                if (ntp->status == SLAVE)
                                        break;
                        }
                                break;
                        for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
                                if (ntp->status == SLAVE)
                                        break;
                        }
+                       ind = findhost(msg->tsp_name);
+                       if (ind < 0) {
+                           syslog(LOG_WARNING,
+                               "DATEREQ from uncontrolled machine");
+                           break;
+                       }
+                       syslog(LOG_DEBUG,
+                           "forwarding date change request for %s",
+                           msg->tsp_name);
+                       (void)strcpy(msg->tsp_name, hostname);
                        answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
                            TSP_DATEACK, ntp);
                        if (answer != NULL) {
                        answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
                            TSP_DATEACK, ntp);
                        if (answer != NULL) {
@@ -209,48 +348,85 @@ loop:
                        trace = OFF;
                        break;
                case TSP_SLAVEUP:
                        trace = OFF;
                        break;
                case TSP_SLAVEUP:
-                       if (!(status & MASTER))
-                               break;
-                       for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
-                               if ((ntp->mask & from.sin_addr.s_addr) ==
-                                   ntp->net) {
-                                       if (ntp->status == MASTER)
-                                               addmach(msg->tsp_name, &from);
-                                       break;
-                               }
+                       if ((status & MASTER) && fromnet->status == MASTER) {
+                               ind = addmach(msg->tsp_name, &from);
+                               newslave(ind, msg->tsp_seq);
                        }
                        break;
                case TSP_ELECTION:
                        }
                        break;
                case TSP_ELECTION:
-                       (void)gettimeofday(&time, (struct timezone *)0);
-                       electiontime = time.tv_sec + delay2;
-                       seq = 0;            /* reset sequence number */
-                       if (time.tv_sec < refusetime)
-                               msg->tsp_type = TSP_REFUSE;
-                       else {
-                               msg->tsp_type = TSP_ACCEPT;
-                               refusetime = time.tv_sec + 30;
-                       }
-                       (void)strcpy(candidate, msg->tsp_name);
-                       (void)strcpy(msg->tsp_name, hostname);
-                       answerdelay();
-                       server = from;
-                       answer = acksend(msg, &server, candidate, TSP_ACK,
-                           (struct netinfo *)NULL);
-                       if (answer == NULL) {
-                               syslog(LOG_ERR, "problem in election\n");
+                       if (fromnet->status == SLAVE) {
+                               (void)gettimeofday(&time, (struct timezone *)0);
+                               electiontime = time.tv_sec + delay2;
+                               seq = 0;            /* reset sequence number */
+                               if (time.tv_sec < refusetime)
+                                       msg->tsp_type = TSP_REFUSE;
+                               else {
+                                       msg->tsp_type = TSP_ACCEPT;
+                                       refusetime = time.tv_sec + 30;
+                               }
+                               (void)strcpy(candidate, msg->tsp_name);
+                               (void)strcpy(msg->tsp_name, hostname);
+                               answerdelay();
+                               server = from;
+                               answer = acksend(msg, &server, candidate, TSP_ACK,
+                                   (struct netinfo *)NULL);
+                               if (answer == NULL)
+                                       syslog(LOG_WARNING,
+                                          "no answer from master candidate\n");
+                       } else {        /* fromnet->status == MASTER */
+                               to.tsp_type = TSP_QUIT;
+                               (void)strcpy(to.tsp_name, hostname);
+                               server = from;
+                               answer = acksend(&to, &server, msg->tsp_name,
+                                   TSP_ACK, (struct netinfo *)NULL);
+                               if (answer == NULL) {
+                                       syslog(LOG_WARNING,
+                                           "election error: no reply to QUIT");
+                               } else {
+                                       (void) addmach(msg->tsp_name, &from);
+                               }
                        }
                        break;
                        }
                        break;
+                case TSP_CONFLICT:
+                       if (fromnet->status != MASTER)
+                               break;
+                        /*
+                         * After a network partition, there can be
+                         * more than one master: the first slave to
+                         * come up will notify here the situation.
+                         */
+                        (void)strcpy(to.tsp_name, hostname);
+
+                        if (fromnet == NULL)
+                                break;
+                        for(;;) {
+                                to.tsp_type = TSP_RESOLVE;
+                                answer = acksend(&to, &fromnet->dest_addr,
+                                    (char *)ANYADDR, TSP_MASTERACK, fromnet);
+                                if (answer == NULL)
+                                        break;
+                                to.tsp_type = TSP_QUIT;
+                                server = from;
+                                msg = acksend(&to, &server, answer->tsp_name,
+                                    TSP_ACK, (struct netinfo *)NULL);
+                                if (msg == NULL) {
+                                        syslog(LOG_WARNING,
+                                           "conflict error: no reply to QUIT");
+                               } else {
+                                        (void) addmach(answer->tsp_name, &from);
+                               }
+                        }
+                        masterup(fromnet);
+                        break;
                case TSP_MSITE:
                case TSP_MSITE:
+                       if (!slavenet)
+                               break;
                        msaveaddr = from;
                        msg->tsp_type = TSP_MSITEREQ;
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
                        msaveaddr = from;
                        msg->tsp_type = TSP_MSITEREQ;
                        msg->tsp_vers = TSPVERSION;
                        (void)strcpy(msg->tsp_name, hostname);
-                       for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
-                               if (ntp->status == SLAVE)
-                                       break;
-                       }
-                       answer = acksend(msg, &ntp->dest_addr, (char *)ANYADDR,
-                           TSP_ACK, ntp);
+                       answer = acksend(msg, &slavenet->dest_addr,
+                                        (char *)ANYADDR, TSP_ACK, slavenet);
                        if (answer != NULL) {
                                msg->tsp_type = TSP_ACK;
                                length = sizeof(struct sockaddr_in);
                        if (answer != NULL) {
                                msg->tsp_type = TSP_ACK;
                                length = sizeof(struct sockaddr_in);
@@ -266,6 +442,18 @@ loop:
                case TSP_ACCEPT:
                case TSP_REFUSE:
                        break;
                case TSP_ACCEPT:
                case TSP_REFUSE:
                        break;
+               case TSP_RESOLVE:
+                       break;
+               case TSP_QUIT:
+                       /* become slave */
+#ifdef MEASURE
+                       if (fp != NULL) {
+                               (void)fclose(fp);
+                               fp = NULL;
+                       }
+#endif
+                       longjmp(jmpenv, 2);
+                       break;
 #ifdef TESTING
                case TSP_TEST:
                        electiontime = 0;
 #ifdef TESTING
                case TSP_TEST:
                        electiontime = 0;
@@ -276,13 +464,81 @@ loop:
                                break;
                        if (trace) {
                                fprintf(fd, "garbage: ");
                                break;
                        if (trace) {
                                fprintf(fd, "garbage: ");
-                               print(msg);
+                               print(msg, &from);
+                       }
+                       break;
+
+               case TSP_LOOP:
+                       /* looking for loops of masters */
+                       if ( !(status & MASTER))
+                               break;
+                       if (fromnet->status == SLAVE) {
+                           if ( !strcmp(msg->tsp_name, hostname)) {
+                                 for(;;) {
+                                   to.tsp_type = TSP_RESOLVE;
+                                   answer = acksend(&to, &fromnet->dest_addr,
+                                       (char *)ANYADDR, TSP_MASTERACK,
+                                       fromnet);
+                                   if (answer == NULL)
+                                           break;
+                                   to.tsp_type = TSP_QUIT;
+                                   (void)strcpy(to.tsp_name, hostname);
+                                   server = from;
+                                   answer = acksend(&to, &server,
+                                       answer->tsp_name, TSP_ACK,
+                                       (struct netinfo *)NULL);
+                                   if (answer == NULL) {
+                                       syslog(LOG_ERR, "loop kill error");
+                                   } else {
+                                       electiontime = 0;
+                                   }
+                                 }
+                           } else {
+                               if (msg->tsp_hopcnt-- <= 0)
+                                   break;
+                               bytenetorder(msg);
+                               ntp = nettab;
+                               for (; ntp != NULL; ntp = ntp->next)
+                                   if (ntp->status == MASTER)
+                                       if (sendto(sock, (char *)msg, 
+                                           sizeof(struct tsp), 0,
+                                           &ntp->dest_addr, length) < 0) {
+                                               syslog(LOG_ERR, "sendto: %m");
+                                               exit(1);
+                                       }
+                           }
+                       } else {
+                           /*
+                            * We should not have received this from a net
+                            * we are master on.  There must be two masters
+                            * in this case.
+                            */
+                           if (fromnet->my_addr.s_addr == from.sin_addr.s_addr)
+                               break;
+                           for (;;) {
+                               to.tsp_type = TSP_RESOLVE;
+                               answer = acksend(&to, &fromnet->dest_addr,
+                                   (char *)ANYADDR, TSP_MASTERACK,
+                                   fromnet);
+                               if (answer == NULL)
+                                       break;
+                               to.tsp_type = TSP_QUIT;
+                               (void)strcpy(to.tsp_name, hostname);
+                               server = from;
+                               answer = acksend(&to, &server, answer->tsp_name,
+                                   TSP_ACK, (struct netinfo *)NULL);
+                               if (answer == NULL) {
+                                       syslog(LOG_ERR, "loop kill error2");
+                               } else {
+                                       (void)addmach(msg->tsp_name, &from);
+                               }
+                           }
                        }
                        break;
                default:
                        if (trace) {
                                fprintf(fd, "garbage: ");
                        }
                        break;
                default:
                        if (trace) {
                                fprintf(fd, "garbage: ");
-                               print(msg);
+                               print(msg, &from);
                        }
                        break;
                }
                        }
                        break;
                }