adding zephyr-im master branch
This commit is contained in:
68
zhm/Makefile.in
Normal file
68
zhm/Makefile.in
Normal file
@ -0,0 +1,68 @@
|
||||
SHELL=@SHELL@
|
||||
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
datadir=@datadir@
|
||||
sysconfdir=@sysconfdir@
|
||||
sbindir=@sbindir@
|
||||
lsbindir=@lsbindir@
|
||||
datarootdir=@datarootdir@
|
||||
|
||||
includedir=@includedir@
|
||||
mandir=@mandir@
|
||||
libdir=@libdir@
|
||||
top_builddir=..
|
||||
|
||||
srcdir=@srcdir@
|
||||
top_srcdir=@top_srcdir@
|
||||
BUILDTOP=..
|
||||
VPATH=@srcdir@
|
||||
LIBTOOL=@LIBTOOL@
|
||||
CC=@CC@
|
||||
INSTALL=@INSTALL@
|
||||
|
||||
editman = sed \
|
||||
-e 's|@datadir[@]|${datadir}|g' \
|
||||
-e 's|@sysconfdir[@]|${sysconfdir}|g' \
|
||||
-e 's|@sbindir[@]|${sbindir}|g' \
|
||||
-e 's|@lsbindir[@]|${lsbindir}|g'
|
||||
|
||||
LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la
|
||||
CPPFLAGS=@CPPFLAGS@
|
||||
CFLAGS=@CFLAGS@
|
||||
ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS}
|
||||
LDFLAGS=@LDFLAGS@
|
||||
HESIOD_LIBS=@HESIOD_LIBS@
|
||||
|
||||
OBJS= timer.o queue.o zhm.o zhm_client.o zhm_server.o
|
||||
|
||||
all: zhm zhm.8
|
||||
|
||||
zhm: ${OBJS} ${LIBZEPHYR}
|
||||
${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBZEPHYR} ${HESIOD_LIBS} -lcom_err
|
||||
|
||||
zhm.8: ${srcdir}/zhm.8.in Makefile
|
||||
${editman} ${srcdir}/$@.in > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${ALL_CFLAGS} $<
|
||||
|
||||
check:
|
||||
|
||||
install: zhm zhm.8
|
||||
${LIBTOOL} --mode=install ${INSTALL} -m 755 zhm ${DESTDIR}${lsbindir}
|
||||
${INSTALL} -m 644 zhm.8 ${DESTDIR}${mandir}/man8
|
||||
|
||||
clean:
|
||||
${LIBTOOL} --mode=clean rm -f zhm
|
||||
rm -f ${OBJS}
|
||||
rm -f zhm.8
|
||||
|
||||
${OBJS}: zhm.h timer.h ${top_srcdir}/h/internal.h ${top_srcdir}/h/sysdep.h
|
||||
${OBJS}: ${BUILDTOP}/h/config.h ${BUILDTOP}/h/zephyr/zephyr.h
|
||||
${OBJS}: ${BUILDTOP}/h/zephyr/zephyr_err.h
|
||||
zhm.o: ${BUILDTOP}/h/zephyr_version.h
|
||||
|
||||
.PHONY: all check install clean
|
||||
|
264
zhm/queue.c
Normal file
264
zhm/queue.c
Normal file
@ -0,0 +1,264 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains the hostmanager queueing routines.
|
||||
*
|
||||
* Created by: David C. Jedlinsky
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1987 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#include "zhm.h"
|
||||
|
||||
#ifndef lint
|
||||
#ifndef SABER
|
||||
static const char rcsid_queue_c[] = "$Id$";
|
||||
#endif /* SABER */
|
||||
#endif /* lint */
|
||||
|
||||
typedef struct _Queue {
|
||||
Timer *timer;
|
||||
int retries;
|
||||
ZNotice_t notice;
|
||||
void *packet;
|
||||
int len;
|
||||
struct sockaddr_in reply;
|
||||
struct _Queue *next, **prev_p;
|
||||
} Queue;
|
||||
|
||||
static Queue *hm_queue;
|
||||
static int retransmits_enabled = 0;
|
||||
|
||||
static Queue *find_notice_in_queue(ZNotice_t *notice);
|
||||
static void queue_timeout(void *arg);
|
||||
|
||||
int rexmit_times[] = { 2, 2, 4, 4, 8, -1 };
|
||||
|
||||
#ifdef DEBUG
|
||||
static void dump_queue(void);
|
||||
#endif
|
||||
|
||||
void
|
||||
init_queue(void)
|
||||
{
|
||||
Queue *q;
|
||||
|
||||
while (hm_queue) {
|
||||
q = hm_queue;
|
||||
if (q->timer)
|
||||
timer_reset(q->timer);
|
||||
free(q->packet);
|
||||
hm_queue = q->next;
|
||||
free(q);
|
||||
}
|
||||
|
||||
DPR("Queue initialized and flushed.\n");
|
||||
}
|
||||
|
||||
Code_t
|
||||
add_notice_to_queue(ZNotice_t *notice,
|
||||
char *packet,
|
||||
struct sockaddr_in *repl,
|
||||
int len)
|
||||
{
|
||||
Queue *entry;
|
||||
|
||||
DPR("Adding notice to queue...\n");
|
||||
if (!find_notice_in_queue(notice)) {
|
||||
entry = (Queue *) malloc(sizeof(Queue));
|
||||
if (entry == NULL)
|
||||
return(ZERR_NONOTICE);
|
||||
entry->retries = 0;
|
||||
entry->packet = (char *) malloc(Z_MAXPKTLEN);
|
||||
if (entry->packet == NULL) {
|
||||
free(entry);
|
||||
return(ZERR_NONOTICE);
|
||||
}
|
||||
memcpy(entry->packet, packet, Z_MAXPKTLEN);
|
||||
entry->len = len;
|
||||
if (ZParseNotice(entry->packet, len, &entry->notice) != ZERR_NONE) {
|
||||
syslog(LOG_ERR, "ZParseNotice failed, but succeeded before");
|
||||
free(entry->packet);
|
||||
} else {
|
||||
entry->reply = *repl;
|
||||
/*LIST_INSERT(&hm_queue, entry);*/
|
||||
|
||||
(entry)->next = *(&hm_queue);
|
||||
if (*&hm_queue) ((*(&hm_queue))->prev_p = &(entry)->next);
|
||||
(*&hm_queue) = (entry);
|
||||
(entry)->prev_p = (&hm_queue);
|
||||
|
||||
}
|
||||
entry->timer = (retransmits_enabled) ?
|
||||
timer_set_rel(rexmit_times[0], queue_timeout, entry) : NULL;
|
||||
}
|
||||
return(ZERR_NONE);
|
||||
}
|
||||
|
||||
Code_t
|
||||
remove_notice_from_queue(ZNotice_t *notice,
|
||||
ZNotice_Kind_t *kind,
|
||||
struct sockaddr_in *repl)
|
||||
{
|
||||
Queue *entry;
|
||||
|
||||
DPR("Removing notice from queue...\n");
|
||||
entry = find_notice_in_queue(notice);
|
||||
if (entry == NULL)
|
||||
return(ZERR_NONOTICE);
|
||||
|
||||
*kind = entry->notice.z_kind;
|
||||
*repl = entry->reply;
|
||||
if (entry->timer)
|
||||
timer_reset(entry->timer);
|
||||
free(entry->packet);
|
||||
/*LIST_DELETE(entry);*/
|
||||
*(entry)->prev_p = (entry)->next;
|
||||
if((entry)->next) ((entry)->next->prev_p = (entry)->prev_p);
|
||||
#ifdef DEBUG
|
||||
dump_queue();
|
||||
#endif /* DEBUG */
|
||||
free(entry);
|
||||
return(ZERR_NONE);
|
||||
}
|
||||
|
||||
/* We have a server; transmit all of our packets. */
|
||||
void
|
||||
retransmit_queue(struct sockaddr_in *sin)
|
||||
{
|
||||
Queue *entry;
|
||||
Code_t ret;
|
||||
|
||||
DPR("Retransmitting queue to new server...\n");
|
||||
ret = ZSetDestAddr(sin);
|
||||
if (ret != ZERR_NONE) {
|
||||
Zperr (ret);
|
||||
com_err("queue", ret, "setting destination");
|
||||
}
|
||||
for (entry = hm_queue; entry; entry = entry->next) {
|
||||
DPR("notice:\n");
|
||||
DPR2("\tz_kind: %d\n", entry->notice.z_kind);
|
||||
DPR2("\tz_port: %u\n", ntohs(entry->notice.z_port));
|
||||
DPR2("\tz_class: %s\n", entry->notice.z_class);
|
||||
DPR2("\tz_clss_inst: %s\n", entry->notice.z_class_inst);
|
||||
DPR2("\tz_opcode: %s\n", entry->notice.z_opcode);
|
||||
DPR2("\tz_sender: %s\n", entry->notice.z_sender);
|
||||
DPR2("\tz_recip: %s\n", entry->notice.z_recipient);
|
||||
ret = ZSendPacket(entry->packet, entry->len, 0);
|
||||
if (ret != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("queue", ret, "sending raw notice");
|
||||
}
|
||||
entry->timer = timer_set_rel(rexmit_times[0], queue_timeout, entry);
|
||||
entry->retries = 0;
|
||||
}
|
||||
retransmits_enabled = 1;
|
||||
}
|
||||
|
||||
/* We lost our server; nuke all of our timers. */
|
||||
void
|
||||
disable_queue_retransmits(void)
|
||||
{
|
||||
Queue *entry;
|
||||
|
||||
for (entry = hm_queue; entry; entry = entry->next) {
|
||||
if (entry->timer)
|
||||
timer_reset(entry->timer);
|
||||
entry->timer = NULL;
|
||||
}
|
||||
retransmits_enabled = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
dump_queue(void)
|
||||
{
|
||||
Queue *entry;
|
||||
char *mp;
|
||||
int ml;
|
||||
|
||||
DPR("Dumping queue...\n");
|
||||
if (!hm_queue) {
|
||||
printf("Queue is empty.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (entry = hm_queue; entry; entry = entry->next) {
|
||||
printf("notice:\n");
|
||||
printf("\tz_kind: %d\n", entry->notice.z_kind);
|
||||
printf("\tz_port: %u\n", ntohs(entry->notice.z_port));
|
||||
printf("\tz_class: %s\n", entry->notice.z_class);
|
||||
printf("\tz_clss_inst: %s\n", entry->notice.z_class_inst);
|
||||
printf("\tz_opcode: %s\n", entry->notice.z_opcode);
|
||||
printf("\tz_sender: %s\n", entry->notice.z_sender);
|
||||
printf("\tz_recip: %s\n", entry->notice.z_recipient);
|
||||
printf("\tMessage:\n");
|
||||
mp = entry->notice.z_message;
|
||||
for (ml = strlen(mp) + 1; ml <= entry->notice.z_message_len; ml++) {
|
||||
printf("\t%s\n", mp);
|
||||
mp += strlen(mp)+1;
|
||||
ml += strlen(mp);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
int
|
||||
queue_len(void)
|
||||
{
|
||||
int length = 0;
|
||||
Queue *entry;
|
||||
|
||||
for (entry = hm_queue; entry; entry = entry->next)
|
||||
length++;
|
||||
return length;
|
||||
}
|
||||
|
||||
static Queue *
|
||||
find_notice_in_queue(ZNotice_t *notice)
|
||||
{
|
||||
Queue *entry;
|
||||
|
||||
for (entry = hm_queue; entry; entry = entry->next) {
|
||||
if (ZCompareUID(&entry->notice.z_uid, ¬ice->z_uid))
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
queue_timeout(void *arg)
|
||||
{
|
||||
Queue *entry = (Queue *) arg;
|
||||
Code_t ret;
|
||||
|
||||
entry->timer = NULL;
|
||||
ret = ZSetDestAddr(&serv_sin);
|
||||
if (ret != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("queue", ret, "setting destination");
|
||||
}
|
||||
entry->retries++;
|
||||
if (rexmit_times[entry->retries] == -1) {
|
||||
new_server(NULL);
|
||||
return;
|
||||
}
|
||||
DPR("Resending notice:\n");
|
||||
DPR2("\tz_kind: %d\n", entry->notice.z_kind);
|
||||
DPR2("\tz_port: %u\n", ntohs(entry->notice.z_port));
|
||||
DPR2("\tz_class: %s\n", entry->notice.z_class);
|
||||
DPR2("\tz_clss_inst: %s\n", entry->notice.z_class_inst);
|
||||
DPR2("\tz_opcode: %s\n", entry->notice.z_opcode);
|
||||
DPR2("\tz_sender: %s\n", entry->notice.z_sender);
|
||||
DPR2("\tz_recip: %s\n", entry->notice.z_recipient);
|
||||
ret = ZSendPacket(entry->packet, entry->len, 0);
|
||||
if (ret != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("queue", ret, "sending raw notice");
|
||||
}
|
||||
entry->timer = timer_set_rel(rexmit_times[entry->retries], queue_timeout,
|
||||
entry);
|
||||
}
|
||||
|
251
zhm/timer.c
Normal file
251
zhm/timer.c
Normal file
@ -0,0 +1,251 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains functions for managing multiple timeouts.
|
||||
*
|
||||
* Created by: John T. Kohl
|
||||
* Derived from timer_manager_ by Ken Raeburn
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
#include "timer.h"
|
||||
|
||||
#ifndef SABER
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
#endif /* lint */
|
||||
#endif /* SABER */
|
||||
|
||||
/*
|
||||
* timer_manager_ -- routines for handling timers in login_shell
|
||||
* (and elsewhere)
|
||||
*
|
||||
* Copyright 1986 Student Information Processing Board,
|
||||
* Massachusetts Institute of Technology
|
||||
*
|
||||
* written by Ken Raeburn
|
||||
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software and its documentation for any purpose and without
|
||||
fee is hereby granted, provided that the above copyright
|
||||
notice appear in all copies and that both that copyright
|
||||
notice and this permission notice appear in supporting
|
||||
documentation, and that the name of M.I.T. and the Student
|
||||
Information Processing Board not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
M.I.T. and the Student Information Processing Board
|
||||
make no representations about the suitability of
|
||||
this software for any purpose. It is provided "as is"
|
||||
without express or implied warranty.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* External functions:
|
||||
*
|
||||
* Timer *timer_set_rel (time_rel, proc, arg)
|
||||
* long time_rel;
|
||||
* void (*proc)();
|
||||
* void *arg;
|
||||
* Timer *timer_set_abs (time_abs, proc, arg)
|
||||
* long time_abs;
|
||||
* void (*proc)();
|
||||
* void *arg;
|
||||
*
|
||||
* void timer_reset(tmr)
|
||||
* Timer *tmr;
|
||||
*
|
||||
* void timer_process()
|
||||
*
|
||||
*/
|
||||
|
||||
/* DELTA is just an offset to keep the size a bit less than a power
|
||||
* of two. It's measured in pointers, so it's 32 bytes on most
|
||||
* systems. */
|
||||
#define DELTA 8
|
||||
#define INITIAL_HEAP_SIZE (1024 - DELTA)
|
||||
|
||||
/* We have three operations which we need to be able to perform
|
||||
* quickly: adding a timer, deleting a timer given a pointer to
|
||||
* it, and determining which timer will be the next to go off. A
|
||||
* heap is an ideal data structure for these purposes, so we use
|
||||
* one. The heap is an array of pointers to timers, and each timer
|
||||
* knows the position of its pointer in the heap.
|
||||
*
|
||||
* Okay, what is the heap, exactly? It's a data structure,
|
||||
* represented as an array, with the invariant condition that
|
||||
* the timeout of heap[i] is less than or equal to the timeout of
|
||||
* heap[i * 2 + 1] and heap[i * 2 + 2] (assuming i * 2 + 1 and
|
||||
* i * 2 + 2 are valid * indices). An obvious consequence of this
|
||||
* is that heap[0] has the lowest timer value, so finding the first
|
||||
* timer to go off is easy. We say that an index i has "children"
|
||||
* i * 2 + 1 and i * 2 + 1, and the "parent" (i - 1) / 2.
|
||||
*
|
||||
* To add a timer to the heap, we start by adding it to the end, and
|
||||
* then keep swapping it with its parent until it has a parent with
|
||||
* a timer value less than its value. With a little bit of thought,
|
||||
* you can see that this preserves the heap property on all indices
|
||||
* of the array.
|
||||
*
|
||||
* To delete a timer at position i from the heap, we discard it and
|
||||
* fill in its position with the last timer in the heap. In order
|
||||
* to restore the heap, we have to consider two cases: the timer
|
||||
* value at i is less than that of its parent, or the timer value at
|
||||
* i is greater than that of one of its children. In the first case,
|
||||
* we propagate the timer at i up the tree, swapping it with its
|
||||
* parent, until the heap is restored; in the second case, we
|
||||
* propagate the timer down the tree, swapping it with its least
|
||||
* child, until the heap is restored. */
|
||||
|
||||
/* In order to ensure that the back pointers from timers are consistent
|
||||
* with the heap pointers, all heap assignments should be done with the
|
||||
* HEAP_ASSIGN() macro, which sets the back pointer and updates the
|
||||
* heap at the same time. */
|
||||
#define PARENT(i) (((i) - 1) / 2)
|
||||
#define CHILD1(i) ((i) * 2 + 1)
|
||||
#define CHILD2(i) ((i) * 2 + 2)
|
||||
#define TIME(i) (heap[i]->abstime)
|
||||
#define HEAP_ASSIGN(pos, tmr) ((heap[pos] = (tmr))->heap_pos = (pos))
|
||||
|
||||
static Timer **heap;
|
||||
static int num_timers = 0;
|
||||
static int heap_size = 0;
|
||||
|
||||
static void timer_botch (void*);
|
||||
static Timer *add_timer (Timer *);
|
||||
|
||||
Timer *
|
||||
timer_set_rel(long time_rel,
|
||||
void (*proc)(void *),
|
||||
void *arg)
|
||||
{
|
||||
Timer *new_t;
|
||||
|
||||
new_t = (Timer *) malloc(sizeof(*new_t));
|
||||
if (new_t == NULL)
|
||||
return(NULL);
|
||||
new_t->abstime = time_rel + time(NULL);
|
||||
new_t->func = proc;
|
||||
new_t->arg = arg;
|
||||
return add_timer(new_t);
|
||||
}
|
||||
|
||||
void
|
||||
timer_reset(Timer *tmr)
|
||||
{
|
||||
int pos, min;
|
||||
|
||||
/* Free the timer, saving its heap position. */
|
||||
pos = tmr->heap_pos;
|
||||
free(tmr);
|
||||
|
||||
if (pos != num_timers - 1) {
|
||||
/* Replace the timer with the last timer in the heap and
|
||||
* restore the heap, propagating the timer either up or
|
||||
* down, depending on which way it violates the heap
|
||||
* property to insert the last timer in place of the
|
||||
* deleted timer. */
|
||||
if (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos))) {
|
||||
do {
|
||||
HEAP_ASSIGN(pos, heap[PARENT(pos)]);
|
||||
pos = PARENT(pos);
|
||||
} while (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos)));
|
||||
HEAP_ASSIGN(pos, heap[num_timers - 1]);
|
||||
} else {
|
||||
while (CHILD2(pos) < num_timers) {
|
||||
min = num_timers - 1;
|
||||
if (TIME(CHILD1(pos)) < TIME(min))
|
||||
min = CHILD1(pos);
|
||||
if (TIME(CHILD2(pos)) < TIME(min))
|
||||
min = CHILD2(pos);
|
||||
HEAP_ASSIGN(pos, heap[min]);
|
||||
pos = min;
|
||||
}
|
||||
if (pos != num_timers - 1)
|
||||
HEAP_ASSIGN(pos, heap[num_timers - 1]);
|
||||
}
|
||||
}
|
||||
num_timers--;
|
||||
}
|
||||
|
||||
|
||||
#define set_timeval(t,s) ((t).tv_sec=(s),(t).tv_usec=0,(t))
|
||||
|
||||
static Timer *
|
||||
add_timer(Timer *new)
|
||||
{
|
||||
int pos;
|
||||
|
||||
/* Create or resize the heap as necessary. */
|
||||
if (heap_size == 0) {
|
||||
heap_size = INITIAL_HEAP_SIZE;
|
||||
heap = (Timer **) malloc(heap_size * sizeof(Timer *));
|
||||
} else if (num_timers >= heap_size) {
|
||||
heap_size = heap_size * 2 + DELTA;
|
||||
heap = (Timer **) realloc(heap, heap_size * sizeof(Timer *));
|
||||
}
|
||||
if (!heap) {
|
||||
free(new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert the Timer *into the heap. */
|
||||
pos = num_timers;
|
||||
while (pos > 0 && new->abstime < TIME(PARENT(pos))) {
|
||||
HEAP_ASSIGN(pos, heap[PARENT(pos)]);
|
||||
pos = PARENT(pos);
|
||||
}
|
||||
HEAP_ASSIGN(pos, new);
|
||||
num_timers++;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void
|
||||
timer_process(void)
|
||||
{
|
||||
Timer *t;
|
||||
timer_proc func;
|
||||
void *arg;
|
||||
|
||||
if (num_timers == 0 || heap[0]->abstime > time(NULL))
|
||||
return;
|
||||
|
||||
/* Remove the first timer from the heap, remembering its
|
||||
* function and argument. */
|
||||
t = heap[0];
|
||||
func = t->func;
|
||||
arg = t->arg;
|
||||
t->func = timer_botch;
|
||||
t->arg = NULL;
|
||||
timer_reset(t);
|
||||
|
||||
/* Run the function. */
|
||||
func(arg);
|
||||
}
|
||||
|
||||
struct timeval *
|
||||
timer_timeout(struct timeval *tvbuf)
|
||||
{
|
||||
if (num_timers > 0) {
|
||||
tvbuf->tv_sec = heap[0]->abstime - time(NULL);
|
||||
if (tvbuf->tv_sec < 0)
|
||||
tvbuf->tv_sec = 0;
|
||||
tvbuf->tv_usec = 0;
|
||||
return tvbuf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
timer_botch(void *arg)
|
||||
{
|
||||
syslog(LOG_CRIT, "timer botch\n");
|
||||
abort();
|
||||
}
|
||||
|
54
zhm/timer.h
Normal file
54
zhm/timer.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains definitions used by timer.c
|
||||
*
|
||||
* Created by: John T. Kohl
|
||||
* Derived from timer_manager_.h by Ken Raeburn
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_H
|
||||
|
||||
/*
|
||||
* timer_manager_ -- routines for handling timers in login_shell
|
||||
* (and elsewhere)
|
||||
*
|
||||
* Copyright 1986 Student Information Processing Board,
|
||||
* Massachusetts Institute of Technology
|
||||
*
|
||||
* written by Ken Raeburn
|
||||
|
||||
Permission to use, copy, modify, and distribute this
|
||||
software and its documentation for any purpose and without
|
||||
fee is hereby granted, provided that the above copyright
|
||||
notice appear in all copies and that both that copyright
|
||||
notice and this permission notice appear in supporting
|
||||
documentation, and that the name of M.I.T. and the Student
|
||||
Information Processing Board not be used in
|
||||
advertising or publicity pertaining to distribution of the
|
||||
software without specific, written prior permission.
|
||||
M.I.T. and the Student Information Processing Board
|
||||
make no representations about the suitability of
|
||||
this software for any purpose. It is provided "as is"
|
||||
without express or implied warranty.
|
||||
|
||||
*/
|
||||
|
||||
typedef void (*timer_proc) __P((void *));
|
||||
|
||||
typedef struct _Timer {
|
||||
int heap_pos; /* Position in timer heap */
|
||||
long abstime;
|
||||
timer_proc func;
|
||||
void *arg;
|
||||
} Timer;
|
||||
|
||||
Timer *timer_set_rel __P((long, timer_proc, void *));
|
||||
Timer *timer_set_abs __P((long, timer_proc, void *));
|
||||
void timer_reset __P((Timer *));
|
||||
void timer_process __P((void));
|
||||
struct timeval *timer_timeout __P((struct timeval *tvbuf));
|
||||
|
||||
#endif /* __TIMER_H */
|
||||
|
106
zhm/zhm.8.in
Normal file
106
zhm/zhm.8.in
Normal file
@ -0,0 +1,106 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.\" Copyright 1987, 1988 by the Massachusetts Institute of Technology
|
||||
.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h
|
||||
.\" specifies the terms and conditions for redistribution.
|
||||
.\"
|
||||
.\"
|
||||
.TH ZHM 8 "November 1, 1988" "MIT Project Athena"
|
||||
.ds ]W MIT Project Athena
|
||||
.SH NAME
|
||||
zhm \- Zephyr HostManager
|
||||
.SH SYNOPSIS
|
||||
.B @lsbindir@/zhm
|
||||
[
|
||||
.BI -d
|
||||
] [
|
||||
.BI -n
|
||||
] [
|
||||
.BI -h
|
||||
] [
|
||||
.BI -r
|
||||
] [
|
||||
.BI -i
|
||||
] [
|
||||
.BI -f
|
||||
] [
|
||||
.BI -N
|
||||
] [
|
||||
.BI server
|
||||
.BI ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Zhm
|
||||
is the link between a client machine and the zephyr server. All
|
||||
notices sent from programs on the client are funneled through
|
||||
.I zhm.
|
||||
This allows all client programs to be much simpler in function, since
|
||||
the HostManager is responsible for handling errors, retransmitting
|
||||
lost notices, and holding all notices until they are acknowledged.
|
||||
.PP
|
||||
The
|
||||
.I -d
|
||||
option turns on debugging mode, and sends its information to syslog
|
||||
LOG_DAEMON messages.
|
||||
.PP
|
||||
The
|
||||
.I -n
|
||||
option causes zhm to not attempt to put itself in the background.
|
||||
.PP
|
||||
The
|
||||
.I -h
|
||||
option causes
|
||||
.I zhm
|
||||
to send a shutdown message and exit upon delivery of a SIGHUP signal.
|
||||
The normal action on SIGHUP is to send a flush notice to the zephyr server.
|
||||
.PP
|
||||
The
|
||||
.I -r
|
||||
option causes
|
||||
.I zhm
|
||||
to send a boot notice to the server and exit when the notice is acknowledged.
|
||||
.PP
|
||||
The
|
||||
.I -i
|
||||
option indicates that
|
||||
.I zhm
|
||||
is being started by
|
||||
.I inetd(8).
|
||||
When this option is specified,
|
||||
.I zhm
|
||||
assumes that file descriptor zero (0) is bound to the UDP datagram port
|
||||
designated for hostmanager use. In this mode, SIGHUP is handled as if the
|
||||
.I -h
|
||||
option were specified.
|
||||
.PP
|
||||
The
|
||||
.I -f
|
||||
option disables the "flush" operation which allows any client to flush
|
||||
all subscriptions for the host.
|
||||
.PP
|
||||
The
|
||||
.I -N
|
||||
option supresses the initial "boot" message that flushes all subscriptions
|
||||
for the host, which is useful if you're restarting zhm on a host that
|
||||
people are using.
|
||||
.PP
|
||||
The optional
|
||||
.I server
|
||||
arguments are used to replace the set of server names supplied by
|
||||
the
|
||||
.I hesiod(3)
|
||||
name server.
|
||||
.SH SEE ALSO
|
||||
zephyr(1), zephyrd(8), inetd(8)
|
||||
.br
|
||||
Project Athena Technical Plan Section E.4.1, `Zephyr Notification
|
||||
Service'
|
||||
.SH AUTHOR
|
||||
.PP
|
||||
David C. Jedlinsky, MIT Project Athena
|
||||
.SH RESTRICTIONS
|
||||
Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
|
||||
All Rights Reserved.
|
||||
.br
|
||||
.I zephyr(1)
|
||||
specifies the terms and conditions for redistribution.
|
623
zhm/zhm.c
Normal file
623
zhm/zhm.c
Normal file
@ -0,0 +1,623 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains the hostmanager client program.
|
||||
*
|
||||
* Created by: David C. Jedlinsky
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1987,1991 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#include "zhm.h"
|
||||
#include <zephyr_version.h>
|
||||
|
||||
static const char rcsid_hm_c[] = "$Id$";
|
||||
|
||||
#ifdef HAVE_HESIOD
|
||||
int use_hesiod = 0;
|
||||
#endif
|
||||
|
||||
#ifdef macII
|
||||
#define srandom srand48
|
||||
#endif
|
||||
|
||||
#define PIDDIR "/var/run/"
|
||||
|
||||
int hmdebug, rebootflag, noflushflag, errflg, dieflag, inetd, oldpid, nofork;
|
||||
int no_server = 1, nservchang, nserv, nclt;
|
||||
int booting = 1, timeout_type, deactivated = 1;
|
||||
int started = 0;
|
||||
long starttime;
|
||||
u_short cli_port;
|
||||
struct sockaddr_in cli_sin, serv_sin, from;
|
||||
int numserv;
|
||||
char **serv_list = NULL;
|
||||
char prim_serv[NS_MAXDNAME], cur_serv[NS_MAXDNAME];
|
||||
char *zcluster;
|
||||
int deactivating = 0;
|
||||
int terminating = 0;
|
||||
struct hostent *hp;
|
||||
char hostname[NS_MAXDNAME], loopback[4];
|
||||
char PidFile[128];
|
||||
|
||||
static RETSIGTYPE deactivate(int);
|
||||
static RETSIGTYPE terminate(int);
|
||||
static void choose_server(void);
|
||||
static void init_hm(void);
|
||||
#ifndef DEBUG
|
||||
static void detach(void);
|
||||
#endif
|
||||
static void send_stats(ZNotice_t *, struct sockaddr_in *);
|
||||
static char *strsave(const char *);
|
||||
|
||||
static RETSIGTYPE
|
||||
deactivate(int ignored)
|
||||
{
|
||||
deactivating = 1;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
terminate(int ignored)
|
||||
{
|
||||
terminating = 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char *argv[])
|
||||
{
|
||||
ZNotice_t notice;
|
||||
ZPacket_t packet;
|
||||
Code_t ret;
|
||||
int opt, pak_len, fd, count;
|
||||
fd_set readers;
|
||||
struct timeval tv;
|
||||
|
||||
sprintf(PidFile, "%szhm.pid", PIDDIR);
|
||||
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
printf("Can't find my hostname?!\n");
|
||||
exit(-1);
|
||||
}
|
||||
prim_serv[0] = '\0';
|
||||
while ((opt = getopt(argc, argv, "drhinfN")) != EOF)
|
||||
switch(opt) {
|
||||
case 'd':
|
||||
hmdebug = 1;
|
||||
break;
|
||||
case 'h':
|
||||
/* Die on SIGHUP */
|
||||
dieflag = 1;
|
||||
break;
|
||||
case 'r':
|
||||
/* Reboot host -- send boot notice -- and exit */
|
||||
rebootflag= 1;
|
||||
break;
|
||||
case 'i':
|
||||
/* inetd operation: don't do bind ourselves, fd 0 is
|
||||
already connected to a socket. Implies -h */
|
||||
inetd = 1;
|
||||
dieflag = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nofork = 1;
|
||||
break;
|
||||
case 'f':
|
||||
noflushflag = 1;
|
||||
break;
|
||||
case 'N':
|
||||
booting = 0;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
errflg++;
|
||||
break;
|
||||
}
|
||||
if (errflg) {
|
||||
fprintf(stderr, "Usage: %s [-d] [-h] [-r] [-n] [-f] [server]\n",
|
||||
argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
numserv = 0;
|
||||
|
||||
/* Override server argument? */
|
||||
if (optind < argc) {
|
||||
if ((hp = gethostbyname(argv[optind++])) == NULL) {
|
||||
printf("Unknown server name: %s\n", argv[optind-1]);
|
||||
} else {
|
||||
strncpy(prim_serv, hp->h_name, sizeof(prim_serv));
|
||||
prim_serv[sizeof(prim_serv) - 1] = '\0';
|
||||
}
|
||||
|
||||
/* argc-optind is the # of other servers on the command line */
|
||||
serv_list = (char **) malloc((argc - optind + 2) * sizeof(char *));
|
||||
if (serv_list == NULL) {
|
||||
printf("Out of memory.\n");
|
||||
exit(-5);
|
||||
}
|
||||
serv_list[numserv++] = prim_serv;
|
||||
for (; optind < argc; optind++) {
|
||||
if ((hp = gethostbyname(argv[optind])) == NULL) {
|
||||
printf("Unknown server name '%s', ignoring\n", argv[optind]);
|
||||
continue;
|
||||
}
|
||||
serv_list[numserv++] = strsave(hp->h_name);
|
||||
}
|
||||
serv_list[numserv] = NULL;
|
||||
}
|
||||
#ifdef HAVE_HESIOD
|
||||
else
|
||||
use_hesiod = 1;
|
||||
#endif
|
||||
|
||||
choose_server();
|
||||
if (*prim_serv == '\0') {
|
||||
printf("No valid primary server found, exiting.\n");
|
||||
exit(ZERR_SERVNAK);
|
||||
}
|
||||
init_hm();
|
||||
started = 1;
|
||||
|
||||
DPR2("zephyr server port: %u\n", ntohs(serv_sin.sin_port));
|
||||
DPR2("zephyr client port: %u\n", ntohs(cli_port));
|
||||
|
||||
/* Main loop */
|
||||
for (;;) {
|
||||
/* Wait for incoming packets or queue timeouts. */
|
||||
DPR("Waiting for a packet...");
|
||||
fd = ZGetFD();
|
||||
FD_ZERO(&readers);
|
||||
FD_SET(fd, &readers);
|
||||
count = select(fd + 1, &readers, NULL, NULL, timer_timeout(&tv));
|
||||
if (count == -1 && errno != EINTR) {
|
||||
syslog(LOG_CRIT, "select() failed: %m");
|
||||
die_gracefully();
|
||||
}
|
||||
|
||||
if (terminating)
|
||||
die_gracefully();
|
||||
|
||||
if (deactivating) {
|
||||
deactivating = 0;
|
||||
if (dieflag) {
|
||||
die_gracefully();
|
||||
} else {
|
||||
choose_server();
|
||||
send_flush_notice(HM_FLUSH);
|
||||
deactivated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
timer_process();
|
||||
|
||||
if (count > 0) {
|
||||
ret = ZReceivePacket(packet, &pak_len, &from);
|
||||
if ((ret != ZERR_NONE) && (ret != EINTR)){
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "receiving notice");
|
||||
} else if (ret != EINTR) {
|
||||
/* Where did it come from? */
|
||||
if ((ret = ZParseNotice(packet, pak_len, ¬ice))
|
||||
!= ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "parsing notice");
|
||||
} else {
|
||||
DPR("Got a packet.\n");
|
||||
DPR("notice:\n");
|
||||
DPR2("\tz_kind: %d\n", notice.z_kind);
|
||||
DPR2("\tz_port: %u\n", ntohs(notice.z_port));
|
||||
DPR2("\tz_class: %s\n", notice.z_class);
|
||||
DPR2("\tz_class_inst: %s\n", notice.z_class_inst);
|
||||
DPR2("\tz_opcode: %s\n", notice.z_opcode);
|
||||
DPR2("\tz_sender: %s\n", notice.z_sender);
|
||||
DPR2("\tz_recip: %s\n", notice.z_recipient);
|
||||
DPR2("\tz_def_format: %s\n", notice.z_default_format);
|
||||
DPR2("\tz_message: %s\n", notice.z_message);
|
||||
if (memcmp(loopback, &from.sin_addr, 4) &&
|
||||
((notice.z_kind == SERVACK) ||
|
||||
(notice.z_kind == SERVNAK) ||
|
||||
(notice.z_kind == HMCTL))) {
|
||||
server_manager(¬ice);
|
||||
} else {
|
||||
if (!memcmp(loopback, &from.sin_addr, 4) &&
|
||||
((notice.z_kind == UNSAFE) ||
|
||||
(notice.z_kind == UNACKED) ||
|
||||
(notice.z_kind == ACKED) ||
|
||||
(notice.z_kind == HMCTL))) {
|
||||
/* Client program... */
|
||||
if (deactivated) {
|
||||
send_boot_notice(HM_BOOT);
|
||||
deactivated = 0;
|
||||
}
|
||||
transmission_tower(¬ice, packet, pak_len);
|
||||
DPR2("Pending = %d\n", ZPending());
|
||||
} else {
|
||||
if (notice.z_kind == STAT) {
|
||||
send_stats(¬ice, &from);
|
||||
} else {
|
||||
syslog(LOG_INFO,
|
||||
"Unknown notice type: %d",
|
||||
notice.z_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
choose_server(void)
|
||||
{
|
||||
#ifdef HAVE_HESIOD
|
||||
int i = 0;
|
||||
char **clust_info, **cpp;
|
||||
|
||||
if (use_hesiod) {
|
||||
|
||||
/* Free up any previously used resources */
|
||||
if (prim_serv[0])
|
||||
i = 1;
|
||||
while (i < numserv)
|
||||
free(serv_list[i++]);
|
||||
if (serv_list)
|
||||
free(serv_list);
|
||||
|
||||
numserv = 0;
|
||||
prim_serv[0] = '\0';
|
||||
|
||||
if ((clust_info = hes_resolve(hostname, "CLUSTER")) == NULL) {
|
||||
zcluster = NULL;
|
||||
} else {
|
||||
for (cpp = clust_info; *cpp; cpp++) {
|
||||
/* Remove the following check once we have changed over to
|
||||
* new Hesiod format (i.e. ZCLUSTER.sloc lookup, no primary
|
||||
* server
|
||||
*/
|
||||
if (!strncasecmp("ZEPHYR", *cpp, 6)) {
|
||||
register char *c;
|
||||
|
||||
if ((c = strchr(*cpp, ' ')) == 0) {
|
||||
printf("Hesiod error getting primary server info.\n");
|
||||
} else {
|
||||
strncpy(prim_serv, c+1, sizeof(prim_serv));
|
||||
prim_serv[sizeof(prim_serv) - 1] = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!strncasecmp("ZCLUSTER", *cpp, 9)) {
|
||||
register char *c;
|
||||
|
||||
if ((c = strchr(*cpp, ' ')) == 0) {
|
||||
printf("Hesiod error getting zcluster info.\n");
|
||||
} else {
|
||||
if ((zcluster = malloc((unsigned)(strlen(c+1)+1)))
|
||||
!= NULL) {
|
||||
strcpy(zcluster, c+1);
|
||||
} else {
|
||||
printf("Out of memory.\n");
|
||||
exit(-5);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (cpp = clust_info; *cpp; cpp++)
|
||||
free(*cpp);
|
||||
}
|
||||
|
||||
if (zcluster == NULL) {
|
||||
if ((zcluster = malloc((unsigned)(strlen("zephyr")+1))) != NULL)
|
||||
strcpy(zcluster, "zephyr");
|
||||
else {
|
||||
printf("Out of memory.\n");
|
||||
exit(-5);
|
||||
}
|
||||
}
|
||||
while ((serv_list = hes_resolve(zcluster, "sloc")) == (char **)NULL) {
|
||||
syslog(LOG_ERR, "No servers or no hesiod");
|
||||
if (!started)
|
||||
return; /* do not hang forever*/
|
||||
/* wait a bit, and try again */
|
||||
sleep(30);
|
||||
}
|
||||
cpp = (char **) malloc(2 * sizeof(char *));
|
||||
if (cpp == NULL) {
|
||||
printf("Out of memory.\n");
|
||||
exit(-5);
|
||||
}
|
||||
if (prim_serv[0])
|
||||
cpp[numserv++] = prim_serv;
|
||||
for (i = 0; serv_list[i]; i++) {
|
||||
/* copy in non-duplicates */
|
||||
/* assume the names returned in the sloc are full domain names */
|
||||
if (!prim_serv[0] || strcasecmp(prim_serv, serv_list[i])) {
|
||||
cpp = (char **) realloc(cpp, (numserv+2) * sizeof(char *));
|
||||
if (cpp == NULL) {
|
||||
printf("Out of memory.\n");
|
||||
exit(-5);
|
||||
}
|
||||
cpp[numserv++] = strsave(serv_list[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; serv_list[i]; i++)
|
||||
free(serv_list[i]);
|
||||
cpp[numserv] = NULL;
|
||||
serv_list = cpp;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!prim_serv[0] && numserv) {
|
||||
srandom(time(NULL));
|
||||
strncpy(prim_serv, serv_list[random() % numserv], sizeof(prim_serv));
|
||||
prim_serv[sizeof(prim_serv) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_hm(void)
|
||||
{
|
||||
struct servent *sp;
|
||||
Code_t ret;
|
||||
#ifndef DEBUG
|
||||
FILE *fp;
|
||||
#endif
|
||||
#ifdef _POSIX_VERSION
|
||||
struct sigaction sa;
|
||||
#endif
|
||||
|
||||
starttime = time((time_t *)0);
|
||||
OPENLOG("hm", LOG_PID, LOG_DAEMON);
|
||||
|
||||
ZSetServerState(1); /* Aargh!!! */
|
||||
if ((ret = ZInitialize()) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "initializing");
|
||||
closelog();
|
||||
exit(-1);
|
||||
}
|
||||
init_queue();
|
||||
|
||||
if (*prim_serv == '\0') {
|
||||
strncpy(prim_serv, *serv_list, sizeof(prim_serv));
|
||||
prim_serv[sizeof(prim_serv) - 1] = '\0';
|
||||
}
|
||||
|
||||
loopback[0] = 127;
|
||||
loopback[1] = 0;
|
||||
loopback[2] = 0;
|
||||
loopback[3] = 1;
|
||||
|
||||
if (inetd) {
|
||||
ZSetFD(0); /* fd 0 is on the socket, thanks to inetd */
|
||||
} else {
|
||||
/* Open client socket, for receiving client and server notices */
|
||||
sp = getservbyname(HM_SVCNAME, "udp");
|
||||
cli_port = (sp) ? sp->s_port : HM_SVC_FALLBACK;
|
||||
|
||||
if ((ret = ZOpenPort(&cli_port)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "opening port");
|
||||
exit(ret);
|
||||
}
|
||||
}
|
||||
cli_sin = ZGetDestAddr();
|
||||
|
||||
sp = getservbyname(SERVER_SVCNAME, "udp");
|
||||
memset(&serv_sin, 0, sizeof(struct sockaddr_in));
|
||||
serv_sin.sin_port = (sp) ? sp->s_port : SERVER_SVC_FALLBACK;
|
||||
|
||||
#ifndef DEBUG
|
||||
if (!inetd && !nofork)
|
||||
detach();
|
||||
|
||||
/* Write pid to file */
|
||||
fp = fopen(PidFile, "w");
|
||||
if (fp != NULL) {
|
||||
fprintf(fp, "%d\n", getpid());
|
||||
fclose(fp);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
if (hmdebug) {
|
||||
syslog(LOG_INFO, "Debugging on.");
|
||||
}
|
||||
|
||||
/* Set up communications with server */
|
||||
/* target is SERVER_SVCNAME port on server machine */
|
||||
|
||||
serv_sin.sin_family = AF_INET;
|
||||
|
||||
/* who to talk to */
|
||||
if ((hp = gethostbyname(prim_serv)) == NULL) {
|
||||
DPR("gethostbyname failed\n");
|
||||
find_next_server(NULL);
|
||||
} else {
|
||||
DPR2("Server = %s\n", prim_serv);
|
||||
strncpy(cur_serv, prim_serv, sizeof(cur_serv));
|
||||
cur_serv[sizeof(cur_serv) - 1] = '\0';
|
||||
memcpy(&serv_sin.sin_addr, hp->h_addr, 4);
|
||||
}
|
||||
|
||||
if (booting)
|
||||
send_boot_notice(HM_BOOT);
|
||||
else
|
||||
send_boot_notice(HM_ATTACH);
|
||||
deactivated = 0;
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = deactivate;
|
||||
sigaction(SIGHUP, &sa, (struct sigaction *)0);
|
||||
sa.sa_handler = terminate;
|
||||
sigaction(SIGTERM, &sa, (struct sigaction *)0);
|
||||
#else
|
||||
signal(SIGHUP, deactivate);
|
||||
signal(SIGTERM, terminate);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
static void
|
||||
detach(void)
|
||||
{
|
||||
/* detach from terminal and fork. */
|
||||
register int i, x = ZGetFD();
|
||||
register long size;
|
||||
|
||||
i = fork();
|
||||
if (i) {
|
||||
if (i < 0)
|
||||
perror("fork");
|
||||
exit(0);
|
||||
}
|
||||
#ifdef _POSIX_VERSION
|
||||
size = sysconf(_SC_OPEN_MAX);
|
||||
#else
|
||||
size = getdtablesize();
|
||||
#endif
|
||||
for (i = 0; i < size; i++)
|
||||
if (i != x)
|
||||
close(i);
|
||||
|
||||
if ((i = open("/dev/tty", O_RDWR, 0666)) < 0)
|
||||
; /* Can't open tty, but don't flame about it. */
|
||||
else {
|
||||
#ifdef TIOCNOTTY
|
||||
/* Necessary for old non-POSIX systems which automatically assign
|
||||
* an opened tty as the controlling terminal of a process which
|
||||
* doesn't already have one. POSIX systems won't include
|
||||
* <sys/ioctl.h> (see ../h/sysdep.h); if TIOCNOTTY is defined anyway,
|
||||
* this is unnecessary but won't hurt. */
|
||||
ioctl(i, TIOCNOTTY, NULL);
|
||||
#endif
|
||||
close(i);
|
||||
}
|
||||
#ifdef _POSIX_VERSION
|
||||
setsid();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static char version[BUFSIZ];
|
||||
|
||||
static char *
|
||||
stats_malloc(size_t size)
|
||||
{
|
||||
char *p = malloc(size);
|
||||
|
||||
if (p == NULL) {
|
||||
printf("Out of memory.\n"); /*XXXXXXXXXXX ? */
|
||||
exit(-5);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
send_stats(ZNotice_t *notice,
|
||||
struct sockaddr_in *sin)
|
||||
{
|
||||
ZNotice_t newnotice;
|
||||
Code_t ret;
|
||||
char *bfr;
|
||||
char *list[20];
|
||||
int len, i, nitems = 10;
|
||||
unsigned long size;
|
||||
extern int Zauthtype; /* XXX this may be changing in the future */
|
||||
|
||||
newnotice = *notice;
|
||||
|
||||
if ((ret = ZSetDestAddr(sin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
newnotice.z_kind = HMACK;
|
||||
|
||||
list[0] = stats_malloc(NS_MAXDNAME);
|
||||
strcpy(list[0], cur_serv);
|
||||
|
||||
list[1] = stats_malloc(64);
|
||||
sprintf(list[1], "%d", queue_len());
|
||||
|
||||
list[2] = stats_malloc(64);
|
||||
sprintf(list[2], "%d", nclt);
|
||||
|
||||
list[3] = stats_malloc(64);
|
||||
sprintf(list[3], "%d", nserv);
|
||||
|
||||
list[4] = stats_malloc(64);
|
||||
sprintf(list[4], "%d", nservchang);
|
||||
|
||||
list[5] = stats_malloc(256);
|
||||
snprintf(list[5], 256, "%s (%d)", ZEPHYR_VERSION_STRING, Zauthtype);
|
||||
list[5][255] = '\0';
|
||||
|
||||
list[6] = stats_malloc(64);
|
||||
if (no_server)
|
||||
sprintf(list[6], "yes");
|
||||
else
|
||||
sprintf(list[6], "no");
|
||||
|
||||
list[7] = stats_malloc(64);
|
||||
sprintf(list[7], "%ld", time((time_t *)0) - starttime);
|
||||
|
||||
#ifdef adjust_size
|
||||
size = (unsigned long)sbrk(0);
|
||||
adjust_size (size);
|
||||
#else
|
||||
size = -1;
|
||||
#endif
|
||||
list[8] = stats_malloc(64);
|
||||
sprintf(list[8], "%ld", size);
|
||||
|
||||
list[9] = stats_malloc(32);
|
||||
strncpy(list[9], MACHINE_TYPE, 32);
|
||||
list[9][31] = '\0';
|
||||
|
||||
/* Since ZFormatRaw* won't change the version number on notices,
|
||||
we need to set the version number explicitly. This code is taken
|
||||
from Zinternal.c, function Z_FormatHeader */
|
||||
if (!*version)
|
||||
sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
|
||||
ZVERSIONMINOR);
|
||||
newnotice.z_version = version;
|
||||
|
||||
if ((ret = ZFormatRawNoticeList(&newnotice, list, nitems, &bfr,
|
||||
&len)) != ZERR_NONE) {
|
||||
syslog(LOG_INFO, "Couldn't format stats packet");
|
||||
} else {
|
||||
if ((ret = ZSendPacket(bfr, len, 0)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending stats");
|
||||
}
|
||||
}
|
||||
free(bfr);
|
||||
for(i=0;i<nitems;i++)
|
||||
free(list[i]);
|
||||
}
|
||||
|
||||
void
|
||||
die_gracefully(void)
|
||||
{
|
||||
syslog(LOG_INFO, "Terminate signal caught...");
|
||||
unlink(PidFile);
|
||||
closelog();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static char *
|
||||
strsave(const char *sp)
|
||||
{
|
||||
register char *ret;
|
||||
|
||||
if((ret = strdup(sp)) == NULL) {
|
||||
abort();
|
||||
}
|
||||
return(ret);
|
||||
}
|
92
zhm/zhm.h
Normal file
92
zhm/zhm.h
Normal file
@ -0,0 +1,92 @@
|
||||
#ifndef __HM_H__
|
||||
#define __HM_H__
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains the hostmanager header file.
|
||||
*
|
||||
* Created by: David C. Jedlinsky
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#include <zephyr/mit-copyright.h>
|
||||
#include <internal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include "timer.h"
|
||||
|
||||
/* These macros are for insertion into and deletion from a singly-linked list
|
||||
* with back pointers to the previous element's next pointer. In order to
|
||||
* make these macros act like expressions, they use the comma operator for
|
||||
* sequenced evaluations of assignment, and "a && b" for "evaluate assignment
|
||||
* b if expression a is true". */
|
||||
#define LIST_INSERT(head, elem) \
|
||||
((elem)->next = *(head), \
|
||||
(*head) && ((*(head))->prev_p = &(elem)->next), \
|
||||
(*head) = (elem), (elem)->prev_p = (head))
|
||||
#define LIST_DELETE(elem) \
|
||||
(*(elem)->prev_p = (elem)->next, \
|
||||
(elem)->next && ((elem)->next->prev_p = (elem)->prev_p))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPR(a) fprintf(stderr, a); fflush(stderr)
|
||||
#define DPR2(a,b) fprintf(stderr, a, b); fflush(stderr)
|
||||
#define Zperr(e) fprintf(stderr, "Error = %d\n", e)
|
||||
#else
|
||||
#define DPR(a)
|
||||
#define DPR2(a,b)
|
||||
#define Zperr(e)
|
||||
#endif
|
||||
|
||||
#define BOOTING 1
|
||||
#define NOTICES 2
|
||||
|
||||
/* main.c */
|
||||
void die_gracefully(void);
|
||||
|
||||
/* zhm_client.c */
|
||||
void transmission_tower(ZNotice_t *, char *, int);
|
||||
Code_t send_outgoing(ZNotice_t *);
|
||||
|
||||
/* queue.c */
|
||||
void init_queue(void);
|
||||
Code_t add_notice_to_queue(ZNotice_t *, char *, struct sockaddr_in *,
|
||||
int);
|
||||
Code_t remove_notice_from_queue(ZNotice_t *, ZNotice_Kind_t *,
|
||||
struct sockaddr_in *);
|
||||
void retransmit_queue(struct sockaddr_in *);
|
||||
void disable_queue_retransmits(void);
|
||||
int queue_len(void);
|
||||
|
||||
/* zhm.c */
|
||||
extern void new_server(char *sugg_serv);
|
||||
extern void send_boot_notice(char *);
|
||||
extern void send_flush_notice(char *);
|
||||
|
||||
/* zhm_server.c */
|
||||
extern void find_next_server(char *);
|
||||
extern void server_manager(ZNotice_t *);
|
||||
|
||||
extern u_short cli_port;
|
||||
extern char **serv_list;
|
||||
extern char cur_serv[], prim_serv[];
|
||||
extern struct sockaddr_in cli_sin, serv_sin, from;
|
||||
extern int no_server, deactivated, noflushflag, rebootflag;
|
||||
extern int timeout_type, hmdebug, nservchang, booting, nclt, nserv, numserv;
|
||||
extern int rexmit_times[];
|
||||
|
||||
#ifdef HAVE_ETEXT
|
||||
extern int etext;
|
||||
#define adjust_size(size) size -= (unsigned long) &etext;
|
||||
#else
|
||||
/* Pick a var that tends to be near the start of data section. */
|
||||
extern char **environ;
|
||||
#define adjust_size(size) size -= (uintptr_t) &environ
|
||||
#endif
|
||||
|
||||
#endif
|
101
zhm/zhm_client.c
Normal file
101
zhm/zhm_client.c
Normal file
@ -0,0 +1,101 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains the hostmanager <--> client interaction routines.
|
||||
*
|
||||
* Created by: David C. Jedlinsky
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1987 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#include "zhm.h"
|
||||
|
||||
#ifndef lint
|
||||
#ifndef SABER
|
||||
static const char rcsid_hm_client_c[] = "$Id$";
|
||||
#endif /* SABER */
|
||||
#endif /* lint */
|
||||
|
||||
void transmission_tower(ZNotice_t *notice,
|
||||
char *packet,
|
||||
int pak_len)
|
||||
{
|
||||
ZNotice_t gack;
|
||||
Code_t ret;
|
||||
struct sockaddr_in gsin;
|
||||
|
||||
nclt++;
|
||||
if (notice->z_kind == HMCTL) {
|
||||
if (!strcmp(notice->z_opcode, CLIENT_FLUSH)) {
|
||||
if (noflushflag)
|
||||
syslog(LOG_INFO, "Client requested hm flush (disabled).");
|
||||
else {
|
||||
send_flush_notice(HM_FLUSH);
|
||||
deactivated = 1;
|
||||
}
|
||||
} else if (!strcmp(notice->z_opcode, CLIENT_NEW_SERVER)) {
|
||||
new_server((char *)NULL);
|
||||
} else {
|
||||
syslog (LOG_INFO, "Bad control notice from client.");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (notice->z_kind != UNSAFE) {
|
||||
gack = *notice;
|
||||
gack.z_kind = HMACK;
|
||||
gack.z_message_len = 0;
|
||||
gack.z_multinotice = "";
|
||||
gsin = cli_sin;
|
||||
gsin.sin_port = from.sin_port;
|
||||
if (gack.z_port == 0)
|
||||
gack.z_port = from.sin_port;
|
||||
DPR2 ("Client Port = %u\n", ntohs(gack.z_port));
|
||||
notice->z_port = gack.z_port;
|
||||
if ((ret = ZSetDestAddr(&gsin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
/* Bounce ACK to library */
|
||||
if ((ret = send_outgoing(&gack)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending raw notice");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!no_server) {
|
||||
DPR2 ("Server Port = %u\n", ntohs(serv_sin.sin_port));
|
||||
if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
if ((ret = ZSendPacket(packet, pak_len, 0)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "while sending raw notice");
|
||||
}
|
||||
}
|
||||
if (add_notice_to_queue(notice, packet, &gsin, pak_len) != ZERR_NONE)
|
||||
syslog(LOG_INFO, "Hey! Insufficient memory to add notice to queue!");
|
||||
}
|
||||
|
||||
Code_t
|
||||
send_outgoing(ZNotice_t *notice)
|
||||
{
|
||||
Code_t retval;
|
||||
char *packet;
|
||||
int length;
|
||||
|
||||
if (!(packet = (char *) malloc((unsigned)sizeof(ZPacket_t))))
|
||||
return(ENOMEM);
|
||||
|
||||
if ((retval = ZFormatSmallRawNotice(notice, packet, &length))
|
||||
!= ZERR_NONE) {
|
||||
free(packet);
|
||||
return(retval);
|
||||
}
|
||||
retval = ZSendPacket(packet, length, 0);
|
||||
free(packet);
|
||||
return(retval);
|
||||
}
|
||||
|
313
zhm/zhm_server.c
Normal file
313
zhm/zhm_server.c
Normal file
@ -0,0 +1,313 @@
|
||||
/* This file is part of the Project Athena Zephyr Notification System.
|
||||
* It contains the hostmanager <--> server interaction routines.
|
||||
*
|
||||
* Created by: David C. Jedlinsky
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 1987 by the Massachusetts Institute of Technology.
|
||||
* For copying and distribution information, see the file
|
||||
* "mit-copyright.h".
|
||||
*/
|
||||
|
||||
#include "zhm.h"
|
||||
|
||||
#ifndef lint
|
||||
#ifndef SABER
|
||||
static const char rcsid_hm_server_c[] = "$Id$";
|
||||
#endif /* SABER */
|
||||
#endif /* lint */
|
||||
|
||||
static void boot_timeout __P((void *));
|
||||
static int get_serv_timeout __P((void));
|
||||
|
||||
static Timer *boot_timer = NULL;
|
||||
static int serv_rexmit_times[] = { 5, 10, 20, 40 };
|
||||
static int serv_timeouts = 0;
|
||||
|
||||
int serv_loop = 0;
|
||||
|
||||
void hm_control(ZNotice_t *);
|
||||
void send_back(ZNotice_t *);
|
||||
|
||||
/* Argument is whether we are actually booting, or just attaching
|
||||
* after a server switch */
|
||||
void
|
||||
send_boot_notice(char *op)
|
||||
{
|
||||
ZNotice_t notice;
|
||||
Code_t ret;
|
||||
|
||||
memset(¬ice, 0, sizeof(ZNotice_t));
|
||||
/* Set up server notice */
|
||||
notice.z_kind = HMCTL;
|
||||
notice.z_port = cli_port;
|
||||
notice.z_class = ZEPHYR_CTL_CLASS;
|
||||
notice.z_class_inst = ZEPHYR_CTL_HM;
|
||||
notice.z_opcode = op;
|
||||
notice.z_sender = "HM";
|
||||
notice.z_recipient = "";
|
||||
notice.z_default_format = "";
|
||||
notice.z_num_other_fields = 0;
|
||||
notice.z_message_len = 0;
|
||||
|
||||
/* Notify server that this host is here */
|
||||
if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending startup notice");
|
||||
}
|
||||
boot_timer = timer_set_rel(get_serv_timeout(), boot_timeout, NULL);
|
||||
}
|
||||
|
||||
/* Argument is whether we are detaching or really going down */
|
||||
void
|
||||
send_flush_notice(char *op)
|
||||
{
|
||||
ZNotice_t notice;
|
||||
Code_t ret;
|
||||
|
||||
memset(¬ice, 0, sizeof(ZNotice_t));
|
||||
/* Set up server notice */
|
||||
notice.z_kind = HMCTL;
|
||||
notice.z_port = cli_port;
|
||||
notice.z_class = ZEPHYR_CTL_CLASS;
|
||||
notice.z_class_inst = ZEPHYR_CTL_HM;
|
||||
notice.z_opcode = op;
|
||||
notice.z_sender = "HM";
|
||||
notice.z_recipient = "";
|
||||
notice.z_default_format = "";
|
||||
notice.z_num_other_fields = 0;
|
||||
notice.z_message_len = 0;
|
||||
|
||||
/* Tell server to lose us */
|
||||
if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending flush notice");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
find_next_server(char *sugg_serv)
|
||||
{
|
||||
struct hostent *hp = 0;
|
||||
int done = 0;
|
||||
char **parse = serv_list;
|
||||
char *new_serv;
|
||||
|
||||
if (sugg_serv) {
|
||||
do {
|
||||
if (!strcmp(*parse, sugg_serv))
|
||||
done = 1;
|
||||
} while ((done == 0) && (*++parse != NULL));
|
||||
}
|
||||
if (done) {
|
||||
if ((hp = gethostbyname(sugg_serv)) != NULL) {
|
||||
DPR2 ("Server = %s\n", sugg_serv);
|
||||
(void)strncpy(cur_serv, sugg_serv, NS_MAXDNAME);
|
||||
cur_serv[NS_MAXDNAME - 1] = '\0';
|
||||
if (hmdebug)
|
||||
syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv);
|
||||
} else {
|
||||
done = 0;
|
||||
}
|
||||
}
|
||||
while (!done) {
|
||||
if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) {
|
||||
serv_loop = 0;
|
||||
if ((hp = gethostbyname(prim_serv)) != NULL) {
|
||||
DPR2 ("Server = %s\n", prim_serv);
|
||||
(void)strncpy(cur_serv, prim_serv, NS_MAXDNAME);
|
||||
cur_serv[NS_MAXDNAME - 1] = '\0';
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (numserv) {
|
||||
case 1:
|
||||
if ((hp = gethostbyname(*serv_list)) != NULL) {
|
||||
DPR2 ("Server = %s\n", *serv_list);
|
||||
(void)strncpy(cur_serv, *serv_list, NS_MAXDNAME);
|
||||
cur_serv[NS_MAXDNAME - 1] = '\0';
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 0:
|
||||
if (rebootflag)
|
||||
die_gracefully();
|
||||
else
|
||||
sleep(1);
|
||||
break;
|
||||
default:
|
||||
do {
|
||||
new_serv = serv_list[random() % numserv];
|
||||
} while (!strcmp(new_serv, cur_serv));
|
||||
|
||||
if ((hp = gethostbyname(new_serv)) != NULL) {
|
||||
DPR2 ("Server = %s\n", new_serv);
|
||||
(void)strncpy(cur_serv, new_serv, NS_MAXDNAME);
|
||||
cur_serv[NS_MAXDNAME - 1] = '\0';
|
||||
done = 1;
|
||||
} else
|
||||
sleep(1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4);
|
||||
nservchang++;
|
||||
}
|
||||
|
||||
void
|
||||
server_manager(ZNotice_t *notice)
|
||||
{
|
||||
if (memcmp((char *)&serv_sin.sin_addr, (char *)&from.sin_addr, 4) ||
|
||||
(serv_sin.sin_port != from.sin_port)) {
|
||||
syslog (LOG_INFO, "Bad notice from port %u.", notice->z_port);
|
||||
} else {
|
||||
/* This is our server, handle the notice */
|
||||
booting = 0;
|
||||
serv_timeouts = 0;
|
||||
if (boot_timer) {
|
||||
timer_reset(boot_timer);
|
||||
boot_timer = NULL;
|
||||
}
|
||||
DPR ("A notice came in from the server.\n");
|
||||
nserv++;
|
||||
switch(notice->z_kind) {
|
||||
case HMCTL:
|
||||
hm_control(notice);
|
||||
break;
|
||||
case SERVNAK:
|
||||
case SERVACK:
|
||||
send_back(notice);
|
||||
break;
|
||||
default:
|
||||
syslog (LOG_INFO, "Bad notice kind!?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hm_control(ZNotice_t *notice)
|
||||
{
|
||||
Code_t ret;
|
||||
struct hostent *hp;
|
||||
char suggested_server[NS_MAXDNAME];
|
||||
unsigned long addr;
|
||||
|
||||
DPR("Control message!\n");
|
||||
if (!strcmp(notice->z_opcode, SERVER_SHUTDOWN)) {
|
||||
if (notice->z_message_len) {
|
||||
addr = inet_addr(notice->z_message);
|
||||
hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);
|
||||
if (hp != NULL) {
|
||||
strncpy(suggested_server, hp->h_name, sizeof(suggested_server));
|
||||
suggested_server[sizeof(suggested_server) - 1] = '\0';
|
||||
new_server(suggested_server);
|
||||
} else {
|
||||
new_server(NULL);
|
||||
}
|
||||
} else {
|
||||
new_server((char *)NULL);
|
||||
}
|
||||
} else if (!strcmp(notice->z_opcode, SERVER_PING)) {
|
||||
notice->z_kind = HMACK;
|
||||
if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
if ((ret = send_outgoing(notice)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending ACK");
|
||||
}
|
||||
if (no_server) {
|
||||
no_server = 0;
|
||||
retransmit_queue(&serv_sin);
|
||||
}
|
||||
} else {
|
||||
syslog (LOG_INFO, "Bad control message.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
send_back(ZNotice_t *notice)
|
||||
{
|
||||
ZNotice_Kind_t kind;
|
||||
struct sockaddr_in repl;
|
||||
Code_t ret;
|
||||
|
||||
if (!strcmp(notice->z_opcode, HM_BOOT) ||
|
||||
!strcmp(notice->z_opcode, HM_ATTACH)) {
|
||||
/* ignore message, just an ack from boot, but exit if we
|
||||
* are rebooting.
|
||||
*/
|
||||
if (rebootflag)
|
||||
die_gracefully();
|
||||
} else {
|
||||
if (remove_notice_from_queue(notice, &kind, &repl) != ZERR_NONE) {
|
||||
syslog (LOG_INFO, "Hey! This packet isn't in my queue!");
|
||||
} else {
|
||||
/* check if client wants an ACK, and send it */
|
||||
if (kind == ACKED) {
|
||||
DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port));
|
||||
if ((ret = ZSetDestAddr(&repl)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "setting destination");
|
||||
}
|
||||
if ((ret = send_outgoing(notice)) != ZERR_NONE) {
|
||||
Zperr(ret);
|
||||
com_err("hm", ret, "sending ACK");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (no_server) {
|
||||
no_server = 0;
|
||||
retransmit_queue(&serv_sin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
new_server(char *sugg_serv)
|
||||
{
|
||||
no_server = 1;
|
||||
syslog (LOG_INFO, "Server went down, finding new server.");
|
||||
send_flush_notice(HM_DETACH);
|
||||
find_next_server(sugg_serv);
|
||||
if (booting || deactivated) {
|
||||
send_boot_notice(HM_BOOT);
|
||||
deactivated = 0;
|
||||
} else {
|
||||
send_boot_notice(HM_ATTACH);
|
||||
}
|
||||
disable_queue_retransmits();
|
||||
}
|
||||
|
||||
static void
|
||||
boot_timeout(void *arg)
|
||||
{
|
||||
serv_timeouts++;
|
||||
new_server(NULL);
|
||||
}
|
||||
|
||||
static int get_serv_timeout(void)
|
||||
{
|
||||
int ind, ntimeouts;
|
||||
|
||||
ind = (numserv == 0) ? serv_timeouts : serv_timeouts / numserv;
|
||||
ntimeouts = sizeof(serv_rexmit_times) / sizeof(*serv_rexmit_times);
|
||||
if (ind >= ntimeouts)
|
||||
ind = ntimeouts - 1;
|
||||
return serv_rexmit_times[ind];
|
||||
}
|
Reference in New Issue
Block a user