265 lines
6.2 KiB
C
265 lines
6.2 KiB
C
/* 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);
|
|
}
|
|
|