* Copyright (c) 1985 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)slave.c 2.22 (Berkeley) 3/2/91";
#include <protocols/timed.h>
long electiontime
, refusetime
, looktime
;
char candidate
[MAXHOSTNAMELEN
];
struct tsp
*msg
, to
, *readmsg();
struct sockaddr_in saveaddr
, msaveaddr
;
struct timeval time
, wait
;
struct tsp
*answer
, *acksend();
struct sockaddr_in server
;
register struct netinfo
*ntp
;
resp
.tsp_type
= TSP_SLAVEUP
;
resp
.tsp_vers
= TSPVERSION
;
(void)strcpy(resp
.tsp_name
, hostname
);
if (sendto(sock
, (char *)&resp
, sizeof(struct tsp
), 0,
(struct sockaddr
*)&slavenet
->dest_addr
,
sizeof(struct sockaddr_in
)) < 0) {
syslog(LOG_ERR
, "sendto: %m");
fp
= fopen(_PATH_MASTERLOG
, "w");
syslog(LOG_INFO
, "THIS MACHINE IS A SUBMASTER");
fprintf(fd
, "THIS MACHINE IS A SUBMASTER\n");
for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
)
if (ntp
->status
== MASTER
)
syslog(LOG_INFO
, "THIS MACHINE IS A SLAVE");
fprintf(fd
, "THIS MACHINE IS A SLAVE\n");
(void)gettimeofday(&time
, (struct timezone
*)0);
electiontime
= time
.tv_sec
+ delay2
;
looktime
= time
.tv_sec
+ delay2
;
length
= sizeof(struct sockaddr_in
);
(void)gettimeofday(&time
, (struct timezone
*)0);
if (time
.tv_sec
> electiontime
) {
fprintf(fd
, "election timer expired\n");
if (looktime
&& time
.tv_sec
> looktime
) {
fprintf(fd
, "Looking for nets to master and loops\n");
for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
if (ntp
->status
== IGNORE
) {
if (ntp
->status
== MASTER
)
* Check to see if we just became master
fp
= fopen(_PATH_MASTERLOG
, "w");
for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
if (ntp
->status
== MASTER
) {
to
.tsp_vers
= TSPVERSION
;
(void)strcpy(to
.tsp_name
, hostname
);
if (sendto(sock
, (char *)&to
, sizeof(struct tsp
), 0,
(struct sockaddr
*)&ntp
->dest_addr
,
sizeof(struct sockaddr_in
)) < 0) {
syslog(LOG_ERR
, "sendto: %m");
(void)gettimeofday(&time
, (struct timezone
*)0);
looktime
= time
.tv_sec
+ delay2
;
wait
.tv_sec
= electiontime
- time
.tv_sec
+ 10;
msg
= readmsg(TSP_ANY
, (char *)ANYADDR
, &wait
, (struct netinfo
*)NULL
);
fprintf(fd
, "slave ignored: ");
if (fromnet
== NULL
|| fromnet
->status
== IGNORE
) {
fprintf(fd
, "slave ignored: ");
if (fromnet
->status
!= SLAVE
)
(void)gettimeofday(&time
, (struct timezone
*)0);
electiontime
= time
.tv_sec
+ delay2
;
if (seq
!= msg
->tsp_seq
) {
if ((status
& SUBMASTER
) == SUBMASTER
) {
synch((msg
->tsp_time
.tv_sec
* 1000) +
(msg
->tsp_time
.tv_usec
/ 1000));
adjclock(&(msg
->tsp_time
));
if (fromnet
->status
!= SLAVE
)
(void)strcpy(olddate
, date());
logwtmp("|", "date", "");
(void)settimeofday(&msg
->tsp_time
,
logwtmp("{", "date", "");
syslog(LOG_NOTICE
, "date changed by %s from: %s",
if ((status
& SUBMASTER
) == SUBMASTER
)
(void)gettimeofday(&time
, (struct timezone
*)0);
electiontime
= time
.tv_sec
+ delay2
;
msg
->tsp_type
= TSP_DATEACK
;
(void)strcpy(msg
->tsp_name
, hostname
);
length
= sizeof(struct sockaddr_in
);
if (sendto(sock
, (char *)msg
,
(struct sockaddr
*)&saveaddr
,
syslog(LOG_ERR
, "sendto: %m");
if (slavenet
&& fromnet
!= slavenet
)
msg
->tsp_type
= TSP_SLAVEUP
;
msg
->tsp_vers
= TSPVERSION
;
(void)strcpy(msg
->tsp_name
, hostname
);
length
= sizeof(struct sockaddr_in
);
if (sendto(sock
, (char *)msg
, sizeof(struct tsp
), 0,
(struct sockaddr
*)&from
, length
) < 0) {
syslog(LOG_ERR
, "sendto: %m");
delay2
= casual((long)MINTOUT
, (long)MAXTOUT
);
(void)gettimeofday(&time
, (struct timezone
*)0);
electiontime
= time
.tv_sec
+ delay2
;
if (fromnet
->status
!= SLAVE
)
(void)gettimeofday(&time
, (struct timezone
*)0);
electiontime
= time
.tv_sec
+ delay2
;
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
)
answer
= acksend(msg
, &ntp
->dest_addr
, (char *)ANYADDR
,
length
= sizeof(struct sockaddr_in
);
if (sendto(sock
, (char *)msg
,
(struct sockaddr
*)&saveaddr
,
syslog(LOG_ERR
, "sendto: %m");
if (status
!= SUBMASTER
|| fromnet
->status
!= MASTER
)
for (ntp
= nettab
; ntp
!= NULL
; ntp
= ntp
->next
) {
if (ntp
->status
== SLAVE
)
ind
= findhost(msg
->tsp_name
);
"DATEREQ from uncontrolled machine");
"forwarding date change request for %s",
(void)strcpy(msg
->tsp_name
, hostname
);
answer
= acksend(msg
, &ntp
->dest_addr
, (char *)ANYADDR
,
msg
->tsp_type
= TSP_DATEACK
;
length
= sizeof(struct sockaddr_in
);
if (sendto(sock
, (char *)msg
,
(struct sockaddr
*)&saveaddr
,
syslog(LOG_ERR
, "sendto: %m");
fd
= fopen(tracefile
, "w");
fprintf(fd
, "Tracing started on: %s\n\n",
fprintf(fd
, "Tracing ended on: %s\n", date());
if ((status
& MASTER
) && fromnet
->status
== MASTER
) {
ind
= addmach(msg
->tsp_name
, &from
);
newslave(ind
, msg
->tsp_seq
);
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
;
msg
->tsp_type
= TSP_ACCEPT
;
refusetime
= time
.tv_sec
+ 30;
(void)strcpy(candidate
, msg
->tsp_name
);
(void)strcpy(msg
->tsp_name
, hostname
);
answer
= acksend(msg
, &server
, candidate
, TSP_ACK
,
"no answer from master candidate\n");
} else { /* fromnet->status == MASTER */
(void)strcpy(to
.tsp_name
, hostname
);
answer
= acksend(&to
, &server
, msg
->tsp_name
,
TSP_ACK
, (struct netinfo
*)NULL
);
"election error: no reply to QUIT");
(void) addmach(msg
->tsp_name
, &from
);
if (fromnet
->status
!= MASTER
)
* 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
);
to
.tsp_type
= TSP_RESOLVE
;
answer
= acksend(&to
, &fromnet
->dest_addr
,
(char *)ANYADDR
, TSP_MASTERACK
, fromnet
);
msg
= acksend(&to
, &server
, answer
->tsp_name
,
TSP_ACK
, (struct netinfo
*)NULL
);
"conflict error: no reply to QUIT");
(void) addmach(answer
->tsp_name
, &from
);
msg
->tsp_type
= TSP_MSITEREQ
;
msg
->tsp_vers
= TSPVERSION
;
(void)strcpy(msg
->tsp_name
, hostname
);
answer
= acksend(msg
, &slavenet
->dest_addr
,
(char *)ANYADDR
, TSP_ACK
, slavenet
);
length
= sizeof(struct sockaddr_in
);
if (sendto(sock
, (char *)msg
,
(struct sockaddr
*)&msaveaddr
,
syslog(LOG_ERR
, "sendto: %m");
fprintf(fd
, "garbage: ");
/* looking for loops of masters */
if (fromnet
->status
== SLAVE
) {
if ( !strcmp(msg
->tsp_name
, hostname
)) {
to
.tsp_type
= TSP_RESOLVE
;
answer
= acksend(&to
, &fromnet
->dest_addr
,
(char *)ANYADDR
, TSP_MASTERACK
,
(void)strcpy(to
.tsp_name
, hostname
);
answer
= acksend(&to
, &server
,
answer
->tsp_name
, TSP_ACK
,
syslog(LOG_ERR
, "loop kill error");
if (msg
->tsp_hopcnt
-- <= 0)
for (; ntp
!= NULL
; ntp
= ntp
->next
)
if (ntp
->status
== MASTER
)
if (sendto(sock
, (char *)msg
,
(struct sockaddr
*)&ntp
->dest_addr
,
syslog(LOG_ERR
, "sendto: %m");
* We should not have received this from a net
* we are master on. There must be two masters
if (fromnet
->my_addr
.s_addr
== from
.sin_addr
.s_addr
)
to
.tsp_type
= TSP_RESOLVE
;
answer
= acksend(&to
, &fromnet
->dest_addr
,
(char *)ANYADDR
, TSP_MASTERACK
,
(void)strcpy(to
.tsp_name
, hostname
);
answer
= acksend(&to
, &server
, answer
->tsp_name
,
TSP_ACK
, (struct netinfo
*)NULL
);
syslog(LOG_ERR
, "loop kill error2");
(void)addmach(msg
->tsp_name
, &from
);
fprintf(fd
, "garbage: ");
* Used before answering a broadcast message to avoid network
* contention and likely collisions.
timeout
.tv_usec
= delay1
;
(void)select(0, (fd_set
*)NULL
, (fd_set
*)NULL
, (fd_set
*)NULL
,