]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/server.c
r4281@bucket (orig r271): kcr | 2008-01-21 14:50:52 -0500
[1ts-debian.git] / zephyr / server / server.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains functions for communication with other servers.
3  *
4  *      Created by:     John T. Kohl
5  *
6  *      $Source: /afs/dev.mit.edu/source/repository/athena/lib/zephyr/server/server.c,v $
7  *      $Author$
8  *
9  *      Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h". 
12  */
13
14 #include <zephyr/mit-copyright.h>
15 #include "zserver.h"
16 #include <sys/socket.h>
17
18 #ifndef lint
19 #ifndef SABER
20 static const char rcsid_server_c[] = "$Id$";
21 #endif
22 #endif
23
24 #define SRV_NACKTAB_HASHSIZE            1023
25 #define SRV_NACKTAB_HASHVAL(which, uid) (((which) ^ (uid).zuid_addr.s_addr ^ \
26                                           (uid).tv.tv_sec ^ (uid).tv.tv_usec) \
27                                          % SRV_NACKTAB_HASHSIZE)
28 /*
29  * Server manager.  Deal with  traffic to and from other servers.
30  *
31  * void server_init()
32  *
33  * void server_shutdown()
34  *
35  * void server_timo(which)
36  *      Server *which;
37  *
38  * void server_dispatch(notice, auth, who)
39  *      ZNotice_t *notice;
40  *      int auth;
41  *      struct sockaddr_in *who;
42  *
43  * void server_recover(client)
44  *      Client *client;
45  *
46  * void server_adispatch(notice, auth, who, server)
47  *      ZNotice_t *notice;
48  *      int auth;
49  *      struct sockaddr_in *who;
50  *      Server *server;
51  *
52  * void server_forward(notice, auth, who)
53  *      ZNotice_t *notice;
54  *      int auth;
55  *      struct sockaddr_in *who;
56  *
57  * Server *server_which_server(who)
58  *      struct sockaddr_in *who;
59  *
60  * void server_kill_clt(client);
61  *      Client *client;
62  *
63  * void server_dump_servers(fp);
64  *      FILE *fp;
65  *
66  * void server_reset();
67  */
68
69 static void server_flush __P((Server *));
70 static void hello_respond __P((struct sockaddr_in *, int, int));
71 static void srv_responded __P((struct sockaddr_in *));
72 static void send_msg __P((struct sockaddr_in *, char *, int));
73 static void send_msg_list __P((struct sockaddr_in *, char *, char **, int,
74                                int));
75 static void srv_nack_cancel __P((ZNotice_t *, struct sockaddr_in *));
76 static void srv_nack_release __P((Server *));
77 static void srv_nack_renumber  __P((int *));
78 static void send_stats __P((struct sockaddr_in *));
79 static void server_queue __P((Server *, int, void *, int,
80                               struct sockaddr_in *));
81 static void server_hello __P((Server *, int));
82 static void setup_server __P((Server *, struct in_addr *));
83 static void srv_rexmit __P((void *));
84 static void server_forw_reliable __P((Server *, caddr_t, int, ZNotice_t *));
85 static Code_t admin_dispatch __P((ZNotice_t *, int, struct sockaddr_in *,
86                                   Server *));
87 static Code_t kill_clt __P((ZNotice_t *, Server *));
88 static Code_t extract_addr __P((ZNotice_t *, struct sockaddr_in *));
89
90 #ifdef notdef
91 static Code_t server_register();
92 #endif
93
94 static struct in_addr *get_server_addrs __P((int *number));
95 static char **get_server_list __P((char *file));
96 static char **get_single_server __P((void));
97 static void free_server_list __P((char **list));
98
99 static Unacked *srv_nacktab[SRV_NACKTAB_HASHSIZE];
100 Server *otherservers;           /* points to an array of the known
101                                    servers */
102 int nservers;                   /* number of other servers */
103 int me_server_idx;              /* # of my entry in the array */
104
105 #define ADJUST          (1)     /* adjust timeout on hello input */
106 #define DONT_ADJUST     (0)     /* don't adjust timeout */
107
108 /* parameters controlling the transitions of the FSM's--patchable with adb */
109 long timo_up = TIMO_UP;
110 long timo_tardy = TIMO_TARDY;
111 long timo_dead = TIMO_DEAD;
112
113 /* counters to measure old protocol use */
114 #ifdef OLD_COMPAT
115 int old_compat_count_uloc = 0;
116 int old_compat_count_ulocate = 0;
117 int old_compat_count_subscr = 0;
118 #endif /* OLD_COMPAT */
119 #ifdef NEW_COMPAT
120 int new_compat_count_uloc = 0;
121 int new_compat_count_subscr = 0;
122 #endif /* NEW_COMPAT */
123
124 #ifdef DEBUG
125 int zalone;
126 #endif /* DEBUG */
127 /*
128  * Initialize the array of servers.  The `limbo' server goes in the first
129  * slot (otherservers[0]).
130  * Contact Hesiod to find all the other servers, allocate space for the
131  * structure, initialize them all to SERV_DEAD with expired timeouts.
132  * Set up a list header for server_forward retransmits.
133  */
134
135 void
136 server_init(void)
137 {
138     int i;
139     struct in_addr *serv_addr, *server_addrs, limbo_addr;
140
141     /* we don't need to mask SIGFPE here since when we are called,
142        the signal handler isn't set up yet. */
143
144     /* talk to hesiod here, set nservers */
145     server_addrs = get_server_addrs(&nservers);
146     if (!server_addrs) {
147         syslog(LOG_ERR, "No servers?!?");
148         exit(1);
149     }
150
151 #ifdef DEBUG
152     if (zalone)
153         nservers = 1;
154     else
155 #endif /* DEBUG */
156         /* increment servers to make room for 'limbo' */
157         nservers++;
158
159     otherservers = (Server *) malloc(nservers * sizeof(Server));
160     me_server_idx = -1;
161
162     /* set up limbo */
163     limbo_addr.s_addr = 0;
164     setup_server(otherservers, &limbo_addr);
165     timer_reset(otherservers[0].timer);
166     otherservers[0].timer = NULL;
167     otherservers[0].queue = NULL;
168     otherservers[0].dumping = 0;
169
170     for (serv_addr = server_addrs, i = 1; i < nservers; serv_addr++, i++) {
171         setup_server(&otherservers[i], serv_addr);
172         /* is this me? */
173         if (serv_addr->s_addr == my_addr.s_addr) {
174             me_server_idx = i;
175             otherservers[i].state = SERV_UP;
176             timer_reset(otherservers[i].timer);
177             otherservers[i].timer = NULL;
178             otherservers[i].queue = NULL;
179             otherservers[i].dumping = 0;
180         }
181     }
182
183     /* free up the addresses */
184     free(server_addrs);
185
186     if (me_server_idx == -1) {
187         syslog(LOG_WARNING, "I'm a renegade server!");
188         otherservers = (Server *) realloc(otherservers,
189                                           ++nservers * sizeof(Server));
190         if (!otherservers) {
191             syslog(LOG_CRIT, "renegade realloc");
192             abort();
193         }
194         setup_server(&otherservers[nservers - 1], &my_addr);
195         /* we are up. */
196         otherservers[nservers - 1].state = SERV_UP;
197
198         /* I don't send hello's to myself--cancel the timer */
199         timer_reset(otherservers[nservers - 1].timer);
200         otherservers[nservers - 1].timer = NULL;
201
202         /* cancel and reschedule all the timers--pointers need
203            adjusting */
204         /* don't reschedule limbo's timer, so start i=1 */
205         for (i = 1; i < nservers - 1; i++) {
206             timer_reset(otherservers[i].timer);
207             /* all the HELLO's are due now */
208             otherservers[i].timer = timer_set_rel(0L, server_timo,
209                                                   &otherservers[i]);
210         }
211         me_server_idx = nservers - 1;
212     }
213
214 }
215
216 /*
217  * server_reset: re-initializes otherservers array by refreshing from Hesiod
218  * or disk file.
219  *
220  * If any server is no longer named in the new list, and that server is in
221  * state SERV_DEAD, it is dropped from the server list.
222  * All other currently-known servers are retained.
223  * Any additional servers not previously known are added to the table.
224  *
225  * WARNING: Don't call this routine if any of the ancestor procedures have a
226  * handle on a particular server other than by indexing on otherservers[].
227  */
228 void
229 server_reset(void)
230 {
231     int num_servers;
232     struct in_addr *server_addrs;
233     struct in_addr *serv_addr;
234     Server *servers;
235     int i, j;
236     int *ok_list_new, *ok_list_old;
237     int num_ok, new_num;
238
239 #ifdef DEBUG
240     if (zalone) {
241         syslog(LOG_INFO, "server_reset while alone, punt");
242         return;
243     }
244 #endif /* DEBUG */
245
246     /* Find out what servers are supposed to be known. */
247     server_addrs = get_server_addrs(&num_servers);
248     if (!server_addrs) {
249         syslog(LOG_ERR, "server_reset no servers. nothing done.");
250         return;
251     }
252     ok_list_new = (int *) malloc(num_servers * sizeof(int));
253     if (!ok_list_new) {
254         syslog(LOG_ERR, "server_reset no mem new");
255         return;
256     }
257     ok_list_old = (int *) malloc(nservers * sizeof(int));
258     if (!ok_list_old) {
259         syslog(LOG_ERR, "server_reset no mem old");
260         free(ok_list_new);
261         return;
262     }
263
264     memset(ok_list_old, 0, nservers * sizeof(int));
265     memset(ok_list_new, 0, num_servers * sizeof(int));
266         
267     /* reset timers--pointers will move */
268     for (j = 1; j < nservers; j++) {    /* skip limbo */
269         if (j == me_server_idx)
270             continue;
271         timer_reset(otherservers[j].timer);
272         otherservers[j].timer = NULL;
273     }
274
275     /* check off entries on new list which are on old list.
276        check off entries on old list which are on new list. */
277
278     /* count limbo as "OK" */
279     num_ok = 1;
280     ok_list_old[0] = 1; /* limbo is OK */
281
282     for (serv_addr = server_addrs, i = 0; i < num_servers; serv_addr++, i++) {
283         for (j = 1; j < nservers; j++) { /* j = 1 since we skip limbo */
284             if (otherservers[j].addr.sin_addr.s_addr == serv_addr->s_addr) {
285                 /* if server is on both lists, mark */
286                 ok_list_new[i] = 1;
287                 ok_list_old[j] = 1;
288                 num_ok++;
289                 break;  /* for j loop */
290             }
291         }
292     }
293
294     /* remove any dead servers on old list not on new list. */
295     if (num_ok < nservers) {
296         int *srv;
297
298         new_num = 1;            /* limbo */
299         /* count number of servers to keep */
300         for (j = 1; j < nservers; j++) {
301             /* since we are never SERV_DEAD, the following
302                test prevents removing ourself from the list */
303             if (ok_list_old[j] || (otherservers[j].state != SERV_DEAD)) {
304                 syslog(LOG_INFO, "keeping server %s",
305                        otherservers[j].addr_str);
306                 new_num++;
307             }
308         }
309         if (new_num < nservers) {
310             servers = (Server *) malloc(new_num * sizeof(Server));
311             if (!servers) {
312                 syslog(LOG_CRIT, "server_reset server malloc");
313                 abort();
314             }
315             i = 1;
316             servers[0] = otherservers[0]; /* copy limbo */
317
318             srv = (int *) malloc(nservers * sizeof(int));
319             memset(srv, 0, nservers * sizeof(int));
320
321             /* copy the kept servers */
322             for (j = 1; j < nservers; j++) { /* skip limbo */
323                 if (ok_list_old[j] ||
324                     otherservers[j].state != SERV_DEAD) {
325                     servers[i] = otherservers[j];
326                     srv[j] = i;
327                     i++;
328                 } else {
329                     syslog(LOG_INFO, "flushing server %s",
330                            otherservers[j].addr_str);
331                     server_flush(&otherservers[j]);
332                     srv[j] = -1;
333                 }
334
335             }
336             srv_nack_renumber(srv);
337
338             free(srv);
339             free(otherservers);
340             otherservers = servers;
341             nservers = new_num;
342         }
343     }
344
345     /* add any new servers on new list not on old list. */
346     new_num = 0;
347     for (i = 0; i < num_servers; i++) {
348         if (!ok_list_new[i])
349             new_num++;
350     }
351
352     /* new_num is number of extras. */
353     nservers += new_num;
354     otherservers = (Server *) realloc(otherservers, nservers * sizeof(Server));
355     if (!otherservers) {
356         syslog(LOG_CRIT, "server_reset realloc");
357         abort();
358     }
359
360     me_server_idx = 0;
361     for (j = 1; j < nservers - new_num; j++) {
362         if (otherservers[j].addr.sin_addr.s_addr == my_addr.s_addr) {
363             me_server_idx = j;
364             break;
365         }
366     }
367     if (!me_server_idx) {
368         syslog(LOG_CRIT, "can't find myself");
369         abort();
370     }
371
372     /* fill in otherservers with the new servers */
373     for (i = 0; i < num_servers; i++) {
374         if (!ok_list_new[i]) {
375             setup_server(&otherservers[nservers - (new_num--)],
376                          &server_addrs[i]);
377             syslog(LOG_INFO, "adding server %s", inet_ntoa(server_addrs[i]));
378         }
379     }
380
381     free(server_addrs);
382     /* reset timers, to go off now.
383        We can't get a time-left indication (bleagh!)
384        so we expire them all now.  This will generally
385        be non-destructive.  We assume that when this code is
386        entered via a SIGHUP trigger that a system wizard
387        is watching the goings-on to make sure things straighten
388        themselves out.
389        */
390     for (i = 1; i < nservers; i++) {    /* skip limbo */
391         if (i != me_server_idx && !otherservers[i].timer) {
392             otherservers[i].timer =
393                 timer_set_rel(0L, server_timo, &otherservers[i]);
394         }
395     }
396     free(ok_list_old);
397     free(ok_list_new);
398
399 }
400
401 /* note: these must match the order given in zserver.h */
402 static char *
403 srv_states[] = {
404     "SERV_UP",
405     "SERV_TARDY",
406     "SERV_DEAD",
407     "SERV_STARTING"
408 };
409 static char *
410 rlm_states[] = {
411     "REALM_UP",
412     "REALM_TARDY",
413     "REALM_DEAD",
414     "REALM_STARTING"
415 };
416
417 /* 
418  * A server timout has expired.  If enough hello's have been unanswered,
419  * change state and act accordingly. Send a "hello" and reset the timer,
420  * incrementing the number of hello's sent.
421  *
422  * See the FSM in the Zephyr document for a better picture of what's
423  * happening here. 
424  */
425
426 void
427 server_timo(void *arg)
428 {
429     Server *which = (Server *) arg;
430     int auth = 0;
431
432     /* change state and reset if appropriate */
433     switch(which->state) {
434       case SERV_DEAD:                   /* leave him dead */
435         server_flush(which);
436         auth = 1;
437         break;
438       case SERV_UP:                     /* he's now tardy */
439         which->state = SERV_TARDY;
440         which->num_hello_sent = 0;
441         which->timeout = timo_tardy;
442         auth = 0;
443         break;
444       case SERV_TARDY:
445       case SERV_STARTING:
446         if (which->num_hello_sent >= ((which->state == SERV_TARDY) ?
447                                       H_NUM_TARDY :
448                                       H_NUM_STARTING)) {
449             /* he hasn't answered, assume DEAD */
450             which->state = SERV_DEAD;
451             which->num_hello_sent = 0;
452             which->timeout = timo_dead;
453             srv_nack_release(which);
454         }
455         auth = 0;
456         break;
457       default:
458         syslog(LOG_ERR,"Bad server state, server 0x%x\n", (int)which);
459         abort();
460     }
461     /* now he's either TARDY, STARTING, or DEAD
462        We send a "hello," which increments the counter */
463     server_hello(which, auth);
464     /* reschedule the timer */
465     which->timer = timer_set_rel(which->timeout, server_timo, which);
466 }
467
468 /*
469  * Dispatch a notice from some other server
470  */
471
472 /*ARGSUSED*/
473 Code_t
474 server_dispatch(ZNotice_t *notice,
475                 int auth,
476                 struct sockaddr_in *who)
477 {
478     Server *server;
479     struct sockaddr_in newwho;
480     Code_t status;
481     String *notice_class;
482
483
484     if (notice->z_kind == SERVACK) {
485         srv_nack_cancel(notice, who);
486         srv_responded(who);
487         return ZERR_NONE;
488     }
489     /* set up a who for the real origin */
490     memset(&newwho, 0, sizeof(newwho));
491     newwho.sin_family = AF_INET;
492     newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
493     newwho.sin_port = notice->z_port;
494
495     server = server_which_server(who);
496
497     /* we can dispatch to routines safely here, since they will
498        return ZSRV_REQUEUE if appropriate.  We bounce this back
499        to the caller, and the caller will re-queue the message
500        for us to process later. */
501
502     notice_class = make_string(notice->z_class, 1);
503
504     if (realm_which_realm(&newwho))
505         status = realm_dispatch(notice, auth, &newwho, server);
506     else if (class_is_admin(notice_class)) {
507         /* admins don't get acked, else we get a packet loop */
508         /* will return  requeue if bdump request and dumping */
509         i_s_admins.val++;
510         return admin_dispatch(notice, auth, who, server);
511     } else if (class_is_control(notice_class)) {
512         status = control_dispatch(notice, auth, &newwho, server);
513         i_s_ctls.val++;
514     } else if (class_is_ulogin(notice_class)) {
515         status = ulogin_dispatch(notice, auth, &newwho, server);
516         i_s_logins.val++;
517     } else if (class_is_ulocate(notice_class)) {
518         status = ulocate_dispatch(notice, auth, &newwho, server);
519         i_s_locates.val++;
520     } else {
521         /* shouldn't come from another server */
522         syslog(LOG_WARNING, "srv_disp: pkt cls %s", notice->z_class);
523         status = ZERR_NONE;     /* XXX */
524     }
525     if (status != ZSRV_REQUEUE)
526         ack(notice, who); /* acknowledge it if processed */
527     free_string(notice_class);
528     return status;
529 }
530
531 #ifdef notdef
532 /*
533  * Register a new server (one not in our list).  This MUST be authenticated.
534  */
535
536 /*ARGSUSED*/
537 static Code_t
538 server_register(notice, auth, who)
539     ZNotice_t *notice;
540     int auth;
541     struct sockaddr_in *who;
542 {
543     Server *temp;
544     int i;
545     long timerval;
546
547     if (who->sin_port != srv_addr.sin_port) {
548         return 1;
549     }
550     /* Not yet... talk to ken about authenticators */
551 #ifdef notdef
552     if (!auth) {
553         zdbug((LOG_DEBUG, "srv_unauth"));
554         return 1;
555     }
556 #endif /* notdef */
557     /* OK, go ahead and set him up. */
558     temp = (Server *) malloc((nservers + 1) * sizeof(Server));
559     if (!temp) {
560         syslog(LOG_CRIT, "srv_reg malloc");
561         return 1;
562     }
563
564     memcpy(temp, otherservers, nservers * sizeof(Server));
565     free(otherservers);
566     otherservers = temp;
567     /* don't reschedule limbo's timer, so start i=1 */
568     for (i = 1; i < nservers; i++) {
569         if (i == me_server_idx) /* don't reset myself */
570             continue;
571         /* reschedule the timers--we moved otherservers */
572         timerval = timer_when(otherservers[i].timer);
573         timer_reset(otherservers[i].timer);
574         otherservers[i].timer = timer_set_abs(timerval, server_timo,
575                                               &otherservers[i]);
576     }
577     setup_server(&otherservers[nservers], &who->sin_addr);
578     otherservers[nservers].state = SERV_STARTING;
579     otherservers[nservers].timeout = timo_tardy;
580     otherservers[nservers].update_queue = NULL;
581     otherservers[nservers].dumping = 0;
582
583     nservers++;
584
585     return 0;
586 }
587 #endif
588
589 /*
590  * Tell the other servers that this client died.
591  */
592
593 void
594 server_kill_clt(Client *client)
595 {
596     int i;
597     char buf[512], *lyst[2];
598     ZNotice_t notice;
599     ZNotice_t *pnotice; /* speed hack */
600     caddr_t pack;
601     int packlen, auth;
602     Code_t retval;
603
604     lyst[0] = inet_ntoa(client->addr.sin_addr),
605     sprintf(buf, "%d", ntohs(client->addr.sin_port));
606     lyst[1] = buf;
607
608     pnotice = &notice;
609
610     memset (&notice, 0, sizeof(notice));
611  
612     pnotice->z_kind = ACKED;
613
614     pnotice->z_port = srv_addr.sin_port;
615     pnotice->z_class = ZEPHYR_ADMIN_CLASS;
616     pnotice->z_class_inst = "";
617     pnotice->z_opcode = ADMIN_KILL_CLT;
618     pnotice->z_sender = myname; /* myname is the hostname */
619     pnotice->z_recipient = "";
620     pnotice->z_default_format = "";
621     pnotice->z_num_other_fields = 0;
622
623     /* XXX */
624     auth = 0;
625
626     /* don't tell limbo to flush, start at 1*/
627     for (i = 1; i < nservers; i++) {
628         if (i == me_server_idx) /* don't xmit to myself */
629             continue;
630         if (otherservers[i].state == SERV_DEAD)
631             continue;
632
633         retval = ZFormatNoticeList(pnotice, lyst, 2, &pack, &packlen,
634                                    auth ? ZAUTH : ZNOAUTH);
635         if (retval != ZERR_NONE) {
636             syslog(LOG_WARNING, "kill_clt format: %s", error_message(retval));
637             return;
638         }
639         server_forw_reliable(&otherservers[i], pack, packlen, pnotice);
640     }
641 }
642
643 /*
644  * A client has died.  remove it
645  */
646
647 static Code_t
648 kill_clt(ZNotice_t *notice,
649          Server *server)
650 {
651     struct sockaddr_in who;
652     Client *client;
653
654     if (extract_addr(notice, &who) != ZERR_NONE)
655         return ZERR_NONE;       /* XXX */
656     client = client_find(&who.sin_addr, notice->z_port);
657     if (!client) {
658         syslog(LOG_NOTICE, "kill_clt: no such client (%s/%d) from %s",
659                inet_ntoa(who.sin_addr), ntohs(who.sin_port),
660                server->addr_str);
661         return ZERR_NONE;       /* XXX */
662     }
663
664     if (zdebug) {
665         syslog(LOG_DEBUG, "kill_clt clt_dereg %s/%d from %s",
666                inet_ntoa(who.sin_addr), ntohs(who.sin_port), server->addr_str);
667     }
668
669     /* remove the locations, too */
670     client_deregister(client, 1);
671     return ZERR_NONE;
672 }
673
674 /*
675  * extract a sockaddr_in from a message body
676  */
677
678 static Code_t
679 extract_addr(ZNotice_t *notice,
680              struct sockaddr_in *who)
681 {
682     char *cp = notice->z_message;
683
684     if (!notice->z_message_len) {
685         syslog(LOG_WARNING, "bad addr pkt");
686         return ZSRV_PKSHORT;
687     }
688     who->sin_addr.s_addr = inet_addr(notice->z_message);
689
690     cp += strlen(cp) + 1;
691     if (cp >= notice->z_message + notice->z_message_len) {
692         syslog(LOG_WARNING, "short addr pkt");
693         return ZSRV_PKSHORT;
694     }
695     who->sin_port = notice->z_port = htons((u_short) atoi(cp));
696     who->sin_family = AF_INET;
697     return ZERR_NONE;
698 }
699
700 /*
701  * Flush all data associated with the server which
702  */
703
704 static void
705 server_flush(Server *which)
706 {
707     srv_nack_release(which);
708 }
709
710 /*
711  * send a hello to which, updating the count of hello's sent
712  * Authenticate if auth is set.
713  */
714
715 static void
716 server_hello(Server *which,
717              int auth)
718 {
719     send_msg(&which->addr, ADMIN_HELLO, auth);
720     which->num_hello_sent++;
721 }
722
723 /*
724  * Handle an ADMIN message from a server
725  */
726
727 /*ARGSUSED*/
728 static Code_t
729 admin_dispatch(ZNotice_t *notice,
730                int auth,
731                struct sockaddr_in *who,
732                Server *server)
733 {
734     char *opcode = notice->z_opcode;
735     Code_t status = ZERR_NONE;
736
737     if (strcmp(opcode, ADMIN_HELLO) == 0) {
738         hello_respond(who, ADJUST, auth);
739     } else if (strcmp(opcode, ADMIN_IMHERE) == 0) {
740         srv_responded(who);
741     } else if (strcmp(opcode, ADMIN_SHUTDOWN) == 0) {
742         if (server) {
743             srv_nack_release(server);
744             server->state = SERV_DEAD;
745             server->timeout = timo_dead;
746             /* don't worry about the timer, it will
747                be set appropriately on the next send */
748         }
749     } else if (strcmp(opcode, ADMIN_BDUMP) == 0) {
750         /* Ignore a brain dump request if this is a brain dump packet
751          * or a packet being processed concurrently during a brain
752          * dump. */
753         if (bdumping || bdump_concurrent)
754             return ZERR_NONE;
755         bdump_get(notice, auth, who, server);
756     } else if (strcmp(opcode, ADMIN_KILL_CLT) == 0) {
757         status = kill_clt(notice, server);
758         if (status == ZERR_NONE)
759             ack(notice, who);
760     } else {
761         syslog(LOG_WARNING, "ADMIN unknown opcode %s",opcode);
762     }
763     return status;
764 }
765
766
767 /*
768  * Handle an ADMIN message from some random client.
769  * For now, assume it's a registration-type message from some other
770  * previously unknown server
771  */
772
773 /*ARGSUSED*/
774 Code_t
775 server_adispatch(ZNotice_t *notice,
776                  int auth,
777                  struct sockaddr_in *who,
778                  Server *server)
779 {
780
781     /* this had better be a HELLO message--start of acquisition
782        protocol, OR a status req packet */
783
784     if (strcmp(notice->z_opcode, ADMIN_STATUS) == 0) {
785         /* status packet */
786         send_stats(who);
787         return ZERR_NONE;
788     }
789
790 #ifdef notdef
791     syslog(LOG_INFO, "disp: new server?");
792     if (server_register(notice, auth, who) != ZERR_NONE) {
793         syslog(LOG_INFO, "new server failed");
794     } else {
795         syslog(LOG_INFO, "new server %s, %d", inet_ntoa(who->sin_addr),
796                ntohs(who->sin_port));
797         hello_respond(who, DONT_ADJUST, auth);
798     }
799 #else
800     syslog(LOG_INFO, "srv_adisp: server attempt from %s",
801            inet_ntoa(who->sin_addr));
802 #endif /* notdef */
803
804     return ZERR_NONE;
805 }
806
807 static void
808 send_stats(struct sockaddr_in *who)
809 {
810     int i;
811     char buf[BUFSIZ];
812     char **responses;
813     int num_resp;
814     char *vers, *pkts, *upt;
815     ZRealm *realm;
816
817     int extrafields = 0;
818 #define NUM_FIXED 3                     /* 3 fixed fields, plus server info */
819                                         /* well, not really...but for
820                                            backward compatibility, we gotta
821                                            do it this way. */
822     vers = get_version();
823
824     sprintf(buf, "%lu pkts", npackets);
825     pkts = strsave(buf);
826     sprintf(buf, "%ld seconds operational",NOW - uptime);
827     upt = strsave(buf);
828
829 #ifdef OLD_COMPAT
830     if (old_compat_count_uloc)
831         extrafields++;
832     if (old_compat_count_ulocate)
833         extrafields++;
834     if (old_compat_count_subscr)
835         extrafields++;
836 #endif /* OLD_COMPAT */
837 #ifdef NEW_COMPAT
838     if (new_compat_count_uloc)
839         extrafields++;
840     if (new_compat_count_subscr)
841         extrafields++;
842 #endif /* NEW_COMPAT */
843     extrafields += nrealms;
844     responses = (char **) malloc((NUM_FIXED + nservers + extrafields) *
845                                  sizeof(char *));
846     responses[0] = vers;
847     responses[1] = pkts;
848     responses[2] = upt;
849
850     num_resp = NUM_FIXED;
851     /* start at 1 and ignore limbo */
852     for (i = 1; i < nservers ; i++) {
853         sprintf(buf, "%s/%s%s", otherservers[i].addr_str,
854                 srv_states[(int) otherservers[i].state],
855                 otherservers[i].dumping ? " (DUMPING)" : "");
856         responses[num_resp++] = strsave(buf);
857     }
858 #ifdef OLD_COMPAT
859     if (old_compat_count_uloc) {
860         sprintf(buf, "%d old old location requests", old_compat_count_uloc);
861         responses[num_resp++] = strsave(buf);
862     }
863     if (old_compat_count_ulocate) {
864         sprintf(buf, "%d old old loc lookup requests",
865                 old_compat_count_ulocate);
866         responses[num_resp++] = strsave(buf);
867     }
868     if (old_compat_count_subscr) {
869         sprintf(buf, "%d old old subscr requests", old_compat_count_subscr);
870         responses[num_resp++] = strsave(buf);
871     }
872 #endif /* OLD_COMPAT */
873 #ifdef NEW_COMPAT
874     if (new_compat_count_uloc) {
875         sprintf(buf, "%d new old location requests", new_compat_count_uloc);
876         responses[num_resp++] = strsave(buf);
877     }
878     if (new_compat_count_subscr) {
879         sprintf(buf, "%d new old subscr requests", new_compat_count_subscr);
880         responses[num_resp++] = strsave(buf);
881     }
882 #endif /* NEW_COMPAT */
883     for (realm = otherrealms, i = 0; i < nrealms ; i++, realm++) {
884       sprintf(buf, "%s(%s)/%s", realm->name, 
885               inet_ntoa((realm->addrs[realm->idx]).sin_addr),
886               rlm_states[(int) realm->state]);
887       responses[num_resp++] = strsave(buf);
888     }
889
890     send_msg_list(who, ADMIN_STATUS, responses, num_resp, 0);
891
892     /* Start at one; don't try to free static version string */
893     for (i = 1; i < num_resp; i++)
894         free(responses[i]);
895     free(responses);
896 }
897
898 /*
899  * Get a list of server addresses.
900 #ifdef HAVE_HESIOD
901  * This list is retrieved from Hesiod.
902 #else
903  * This list is read from a file.
904 #endif
905  * Return a pointer to an array of allocated storage.  This storage is
906  * freed by the caller.
907  */
908
909 static struct in_addr *
910 get_server_addrs(int *number)
911 {
912     int i;
913     char **server_hosts = NULL;
914     char **server_hosts_free = NULL;
915     char **cpp;
916     struct in_addr *addrs;
917     struct in_addr *addr;
918     struct hostent *hp;
919
920     server_hosts = get_server_list(list_file);
921     server_hosts_free = server_hosts;
922 #ifdef HAVE_HESIOD
923     if (!server_hosts)
924         server_hosts = hes_resolve("zephyr","sloc");
925 #endif
926     if (!server_hosts) {
927         server_hosts = get_single_server();
928         server_hosts_free = server_hosts;
929     }
930     if (!server_hosts)
931         return NULL;
932     /* count up */
933     i = 0;
934     for (cpp = server_hosts; *cpp; cpp++)
935         i++;
936         
937     addrs = (struct in_addr *) malloc(i * sizeof(struct in_addr));
938
939     /* Convert to in_addr's */
940     for (cpp = server_hosts, addr = addrs, i = 0; *cpp; cpp++) {
941         hp = gethostbyname(*cpp);
942         if (hp) {
943             memcpy(addr, hp->h_addr, sizeof(struct in_addr));
944             addr++, i++;
945         } else {
946             syslog(LOG_WARNING, "hostname failed, %s", *cpp);
947         }
948     }
949     *number = i;
950     if (server_hosts_free)
951       free_server_list(server_hosts_free);
952     return addrs;
953 }
954
955 static int nhosts = 0;
956
957 /*
958  * read "file" to get a list of names of hosts to peer with.
959  * The file should contain a list of host names, one per line.
960  */
961
962 static char **
963 get_server_list(char *file)
964 {
965     FILE *fp;
966     char buf[MAXHOSTNAMELEN];
967     char **ret_list;
968     int nused = 0;
969     char *newline;
970
971     fp = fopen(file, "r");
972     if (!fp)
973         return NULL;
974     /* start with 16, realloc if necessary */
975     nhosts = 16;
976     ret_list = (char **) malloc(nhosts * sizeof(char *));
977     if (!ret_list)
978         return NULL;
979
980     while (fgets(buf, MAXHOSTNAMELEN, fp)) {
981         /* nuke the newline, being careful not to overrun
982            the buffer searching for it with strlen() */
983         buf[MAXHOSTNAMELEN - 1] = '\0';
984         newline = strchr(buf, '\n');
985         if (newline)
986             *newline = '\0';
987
988         if (nused + 1 >= nhosts) {
989             /* get more pointer space if necessary */
990             /* +1 to leave room for null pointer */
991             ret_list = (char **) realloc(ret_list, nhosts * 2);
992             nhosts = nhosts * 2;
993         }
994         ret_list[nused++] = strsave(buf);
995     }
996     fclose(fp);
997     if (!nused) {
998         free(ret_list);
999         return NULL;
1000     }
1001     ret_list[nused] = NULL;
1002     return ret_list;
1003 }
1004
1005 static char **
1006 get_single_server(void)
1007 {
1008     char buf[MAXHOSTNAMELEN];
1009     char **ret_list;
1010     int nused = 0;
1011     nhosts = 2;
1012     ret_list = (char **) malloc(nhosts * sizeof(char *));
1013     if (!ret_list)
1014         return NULL;
1015     if (gethostname(buf, sizeof(buf)) < 0) {
1016         free(ret_list);
1017         return NULL;
1018     }
1019     ret_list[nused++] = strsave(buf);
1020     ret_list[nused] = NULL;
1021     return ret_list;
1022 }
1023
1024 /* 
1025  * free storage allocated by get_server_list
1026  */
1027 static void
1028 free_server_list(char **list)
1029 {
1030     char **orig_list = list;
1031
1032     if (!nhosts)                        /* nothing allocated */
1033         return;
1034     for (; *list; list++)
1035         free(*list);
1036     free(orig_list);
1037     return;
1038 }
1039
1040 /*
1041  * initialize the server structure for address addr, and set a timer
1042  * to go off immediately to send hello's to other servers.
1043  */
1044
1045 static void
1046 setup_server(Server *server,
1047              struct in_addr *addr)
1048 {
1049     server->state = SERV_DEAD;
1050     server->timeout = timo_dead;
1051     server->num_hello_sent = 0;
1052     server->addr.sin_family = AF_INET;
1053     /* he listens to the same port we do */
1054     server->addr.sin_port = srv_addr.sin_port;
1055     server->addr.sin_addr = *addr;
1056     strcpy(server->addr_str, inet_ntoa(*addr));
1057     server->timer = timer_set_rel(0L, server_timo, server);
1058     server->queue = NULL;
1059     server->dumping = 0;
1060 }
1061
1062 /*
1063  * Someone sent us a hello message, respond to them.
1064  */
1065
1066 static void
1067 hello_respond(struct sockaddr_in *who,
1068               int adj,
1069               int auth)
1070 {
1071     Server *which;
1072
1073     send_msg(who, ADMIN_IMHERE, auth);
1074     if (adj != ADJUST)
1075         return;
1076
1077     /* If we think he's down, schedule an immediate HELLO. */
1078
1079     which = server_which_server(who);
1080     if (!which)
1081         return;
1082
1083     switch (which->state) {
1084       case SERV_DEAD:
1085         /* he said hello, we thought he was dead.
1086            reschedule his hello for now. */
1087         timer_reset(which->timer);
1088         which->timer = timer_set_rel(0L, server_timo, which);
1089         break;
1090       case SERV_STARTING:
1091       case SERV_TARDY:
1092       case SERV_UP:
1093       default:
1094         break;
1095     }
1096 }    
1097
1098 /*
1099  * return the server descriptor for server at who
1100  */
1101
1102 Server *
1103 server_which_server(struct sockaddr_in *who)
1104 {
1105     Server *server;
1106     int i;
1107
1108     if (who->sin_port != srv_addr.sin_port)
1109         return NULL;
1110
1111     /* don't check limbo */
1112     for (server = &otherservers[1], i = 1; i < nservers; i++, server++) {
1113         if (server->addr.sin_addr.s_addr == who->sin_addr.s_addr)
1114             return server;
1115     }
1116     return NULL;
1117 }
1118
1119 /*
1120  * We received a response to a hello packet or an ack. Adjust server state
1121  * appropriately.
1122  */
1123 static void
1124 srv_responded(struct sockaddr_in *who)
1125 {
1126     Server *which = server_which_server(who);
1127
1128     if (!which) {
1129         syslog(LOG_ERR, "hello input from non-server?!");
1130         return;
1131     }
1132
1133     switch (which->state) {
1134       case SERV_DEAD:
1135         /* he responded, we thought he was dead. mark as starting
1136            and negotiate */
1137         which->state = SERV_STARTING;
1138         which->timeout = timo_tardy;
1139         timer_reset(which->timer);
1140         which->timer = timer_set_rel(0L, server_timo, which);
1141
1142       case SERV_STARTING:
1143         /* here we negotiate and set up a braindump */
1144         if (bdump_socket < 0)
1145             bdump_offer(who);
1146         break;
1147
1148       case SERV_TARDY:
1149         which->state = SERV_UP;
1150         /* Fall through. */
1151
1152       case SERV_UP:
1153         /* reset the timer and counts */
1154         which->num_hello_sent = 0;
1155         which->timeout = timo_up;
1156         timer_reset(which->timer);
1157         which->timer = timer_set_rel(which->timeout, server_timo, which);
1158         break;
1159     }
1160 }
1161
1162 /*
1163  * Send each of the other servers a shutdown message.
1164  */
1165
1166 void
1167 server_shutdown(void)
1168 {
1169     int i;
1170
1171     /* don't tell limbo to go away, start at 1*/
1172     for (i = 1; i < nservers; i++)
1173         send_msg(&otherservers[i].addr, ADMIN_SHUTDOWN, 1);
1174 }
1175
1176 /*
1177  * send a message to who with admin class and opcode and clinst as specified.
1178  * auth is set if we want to send authenticated
1179  */
1180
1181 static void
1182 send_msg(struct sockaddr_in *who,
1183          char *opcode,
1184          int auth)
1185 {
1186     ZNotice_t notice;
1187     ZNotice_t *pnotice; /* speed hack */
1188     char *pack;
1189     int packlen;
1190     Code_t retval;
1191
1192     pnotice = &notice;
1193
1194     memset (&notice, 0, sizeof(notice));
1195
1196     pnotice->z_kind = ACKED;
1197
1198     pnotice->z_port = srv_addr.sin_port;
1199     pnotice->z_class = ZEPHYR_ADMIN_CLASS;
1200     pnotice->z_class_inst = "";
1201     pnotice->z_opcode = opcode;
1202     pnotice->z_sender = myname; /* myname is the hostname */
1203     pnotice->z_recipient = "";
1204     pnotice->z_default_format = "";
1205     pnotice->z_message = NULL;
1206     pnotice->z_message_len = 0;
1207     pnotice->z_num_other_fields = 0;
1208
1209     /* XXX for now, we don't do authentication */
1210     auth = 0;
1211
1212     retval = ZFormatNotice(pnotice, &pack, &packlen, auth ? ZAUTH : ZNOAUTH);
1213     if (retval != ZERR_NONE) {
1214         syslog(LOG_WARNING, "snd_msg format: %s", error_message(retval));
1215         return;
1216     }
1217     retval = ZSetDestAddr(who);
1218     if (retval != ZERR_NONE) {
1219         syslog(LOG_WARNING, "snd_msg set addr: %s", error_message(retval));
1220         free(pack);
1221         return;
1222     }
1223     /* don't wait for ack */
1224     retval = ZSendPacket(pack, packlen, 0);
1225     if (retval != ZERR_NONE)
1226         syslog(LOG_WARNING, "snd_msg xmit: %s", error_message(retval));
1227     free(pack);
1228 }
1229
1230 /*
1231  * send a notice with a message to who with admin class and opcode and
1232  * message body as specified.
1233  * auth is set if we want to send authenticated
1234  * server_idx is -1 if we are sending to a client, or the server index
1235  *  if we are sending to a server.
1236  */
1237
1238 static void
1239 send_msg_list(struct sockaddr_in *who,
1240               char *opcode,
1241               char **lyst,
1242               int num,
1243               int auth)
1244 {
1245     ZNotice_t notice;
1246     char *pack;
1247     int packlen;
1248     Code_t retval;
1249
1250     memset (&notice, 0, sizeof(notice));
1251
1252     notice.z_kind = UNSAFE;
1253     notice.z_port = srv_addr.sin_port;
1254     notice.z_class = ZEPHYR_ADMIN_CLASS;
1255     notice.z_class_inst = "";
1256     notice.z_opcode = opcode;
1257     notice.z_sender = myname;   /* myname is the hostname */
1258     notice.z_recipient = "";
1259     notice.z_default_format = "";
1260     notice.z_message = NULL;
1261     notice.z_message_len = 0;
1262     notice.z_num_other_fields = 0;
1263
1264     /* XXX for now, we don't do authentication */
1265     auth = 0;
1266
1267     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen,
1268                                auth ? ZAUTH : ZNOAUTH);
1269     if (retval != ZERR_NONE) {
1270         syslog(LOG_WARNING, "snd_msg_lst format: %s", error_message(retval));
1271         return;
1272     }
1273     retval = ZSetDestAddr(who);
1274     if (retval != ZERR_NONE) {
1275         syslog(LOG_WARNING, "snd_msg_lst set addr: %s", error_message(retval));
1276         free(pack);
1277         return;
1278     }
1279     xmit_frag(&notice, pack, packlen, 0);
1280     free(pack);
1281 }
1282
1283 /*
1284  * Forward the notice to the other servers
1285  */
1286 /*ARGSUSED*/
1287 void
1288 server_forward(ZNotice_t *notice,
1289                int auth,
1290                struct sockaddr_in *who)
1291 {
1292     int i;
1293     caddr_t pack;
1294     int packlen;
1295     Code_t retval;
1296
1297     /* don't send to limbo */
1298     for (i = 1; i < nservers; i++) {
1299         if (i == me_server_idx) /* don't xmit to myself */
1300             continue;
1301         if (otherservers[i].state == SERV_DEAD &&
1302             otherservers[i].dumping == 0) {
1303             /* if we are dumping to him, we want to
1304                queue it, even if he's dead */
1305             continue;
1306         }
1307
1308         pack = malloc(sizeof(ZPacket_t));
1309         if (!pack) {
1310             syslog(LOG_CRIT, "srv_fwd malloc");
1311             abort();
1312         }
1313         retval = ZNewFormatSmallRawNotice(notice, pack, &packlen);
1314         if (retval != ZERR_NONE) {
1315             syslog(LOG_WARNING, "srv_fwd format: %s", error_message(retval));
1316             continue;
1317         }
1318         if (otherservers[i].dumping) {
1319             server_queue(&otherservers[i], packlen, pack, auth, who);
1320             continue;
1321         }
1322         server_forw_reliable(&otherservers[i], pack, packlen, notice);
1323     }
1324 }
1325
1326 static void
1327 server_forw_reliable(Server *server,
1328                      caddr_t pack,
1329                      int packlen,
1330                      ZNotice_t *notice)
1331 {
1332     Code_t retval;
1333     Unacked *nacked;
1334     int hashval;
1335
1336     retval = ZSetDestAddr(&server->addr);
1337     if (retval != ZERR_NONE) {
1338         syslog(LOG_WARNING, "srv_fwd_rel set addr: %s", error_message(retval));
1339         free(pack);
1340         return;
1341     }
1342     retval = ZSendPacket(pack, packlen, 0);
1343     if (retval != ZERR_NONE) {
1344         syslog(LOG_WARNING, "srv_fwd xmit: %s", error_message(retval));
1345         free(pack);
1346         return;
1347     }                   
1348     /* now we've sent it, mark it as not ack'ed */
1349                 
1350     nacked = (Unacked *) malloc(sizeof(Unacked));
1351     if (!nacked) {
1352         /* no space: just punt */
1353         syslog(LOG_ERR, "srv_forw_rel nack malloc");
1354         free(pack);
1355         return;
1356     }
1357
1358     nacked->client = NULL;
1359     nacked->rexmits = 0;
1360     nacked->packet = pack;
1361     nacked->dest.srv_idx = server - otherservers;
1362     nacked->packsz = packlen;
1363     nacked->uid = notice->z_uid;
1364     nacked->timer = timer_set_rel(rexmit_times[0], srv_rexmit, nacked);
1365     hashval = SRV_NACKTAB_HASHVAL(nacked->dest.srv_idx, nacked->uid);
1366     Unacked_insert(&srv_nacktab[hashval], nacked);
1367 }
1368
1369 /*
1370  * send the queued message for the server.
1371  */
1372
1373 void
1374 server_send_queue(Server *server)
1375 {
1376     Pending *pending;
1377     ZNotice_t notice;
1378     Code_t status;
1379
1380     while (server->queue) {
1381         pending = server_dequeue(server);
1382         status = ZParseNotice(pending->packet, pending->len, &notice);
1383         if (status != ZERR_NONE) {
1384             syslog(LOG_ERR, "ssq bad notice parse (%s): %s",
1385                    inet_ntoa(pending->who.sin_addr), error_message(status));
1386         } else {
1387             server_forw_reliable(server, pending->packet, pending->len,
1388                                  &notice);
1389             free(pending);
1390             /* ACK handling routines will free the packet */
1391         }
1392     }
1393 }
1394
1395 /*
1396  * a server has acknowledged a message we sent to him; remove it from
1397  * server unacked queue
1398  */
1399
1400 static void
1401 srv_nack_cancel(ZNotice_t *notice,
1402                 struct sockaddr_in *who)
1403 {
1404     Server *server = server_which_server(who);
1405     Unacked *nacked;
1406     int hashval;
1407
1408     if (!server) {
1409         syslog(LOG_ERR, "non-server ack?");
1410         return;
1411     }
1412     hashval = SRV_NACKTAB_HASHVAL(server - otherservers, notice->z_uid);
1413     for (nacked = srv_nacktab[hashval]; nacked; nacked = nacked->next) {
1414         if (nacked->dest.srv_idx == server - otherservers
1415             && ZCompareUID(&nacked->uid, &notice->z_uid)) {
1416             timer_reset(nacked->timer);
1417             free(nacked->packet);
1418             Unacked_delete(nacked);
1419             free(nacked);
1420             return;
1421         }
1422     }
1423 }
1424
1425 /*
1426  * retransmit a message to another server
1427  */
1428
1429 static void
1430 srv_rexmit(void *arg)
1431 {
1432     Unacked *packet = (Unacked *) arg;
1433     Code_t retval;
1434     /* retransmit the packet */
1435         
1436     if (otherservers[packet->dest.srv_idx].state == SERV_DEAD) {
1437         Unacked_delete(packet);
1438         free(packet->packet);
1439         srv_nack_release(&otherservers[packet->dest.srv_idx]);
1440         free(packet);
1441         return;
1442     }
1443     retval = ZSetDestAddr(&otherservers[packet->dest.srv_idx].addr);
1444     if (retval != ZERR_NONE) {
1445         syslog(LOG_WARNING, "srv_rexmit set addr: %s", error_message(retval));
1446     } else {
1447         retval = ZSendPacket(packet->packet, packet->packsz, 0);
1448         if (retval != ZERR_NONE)
1449             syslog(LOG_WARNING, "srv_rexmit xmit: %s",
1450                    error_message(retval));
1451     }
1452
1453     /* reset the timer */
1454     if (rexmit_times[packet->rexmits + 1] != -1)
1455         packet->rexmits++;
1456     packet->timer = timer_set_rel(rexmit_times[packet->rexmits], srv_rexmit,
1457                                   packet);
1458 }
1459
1460 /*
1461  * Clean up the not-yet-acked queue and release anything destined
1462  * to the server.
1463  */
1464
1465 static void
1466 srv_nack_release(Server *server)
1467 {
1468     int i;
1469     Unacked *nacked, *next;
1470
1471     for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) {
1472         for (nacked = srv_nacktab[i]; nacked; nacked = next) {
1473             next = nacked->next;
1474             if (nacked->dest.srv_idx == server - otherservers) {
1475                 timer_reset(nacked->timer);
1476                 Unacked_delete(nacked);
1477                 free(nacked->packet);
1478                 free(nacked);
1479             }
1480         }
1481     }
1482 }
1483
1484 /*
1485  * Adjust indices of not-yet-acked packets sent to other servers to
1486  * continue to refer to the correct server.
1487  */
1488
1489 static void
1490 srv_nack_renumber (int *new_idx)
1491 {
1492     /* XXX release any private queue for this server */
1493     Unacked *nacked;
1494     int idx, i;
1495
1496     /* search the not-yet-acked list for anything destined to 'from', and
1497        change the index to 'to'. */
1498     for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) {
1499         for (nacked = srv_nacktab[i]; nacked; nacked = nacked->next) {
1500             idx = new_idx[nacked->dest.srv_idx];
1501             if (idx < 0) {
1502                 syslog(LOG_ERR, "srv_nack_renumber error: [%d]=%d",
1503                        nacked->dest.srv_idx, idx);
1504                 idx = 0;
1505             }
1506             nacked->dest.srv_idx = idx;
1507         }
1508     }
1509 }
1510
1511 /*
1512  * Queue this notice to be transmitted to the server when it is ready.
1513  */
1514 static void
1515 server_queue(Server *server,
1516              int len,
1517              void *pack,
1518              int auth,
1519              struct sockaddr_in *who)
1520 {
1521     Pending *pending;
1522
1523     pending = (Pending *) malloc(sizeof(Pending));
1524     if (!pending) {
1525         syslog(LOG_CRIT, "update_queue malloc");
1526         abort();
1527     }
1528     pending->packet = pack;
1529     pending->len = len;
1530     pending->auth = auth;
1531     pending->who = *who;
1532     pending->next = NULL;
1533
1534     /* put it on the end of the list */
1535     if (server->queue)
1536         server->queue_last->next = pending;
1537     else
1538         server->queue = server->queue_last = pending;
1539 }
1540
1541 /*
1542  * Pull a notice off the hold queue.
1543  */
1544
1545 Pending *
1546 server_dequeue(Server *server)
1547 {
1548     Pending *pending;
1549         
1550     if (!server->queue)
1551         return NULL;
1552     pending = server->queue;
1553     server->queue = pending->next;
1554     return pending;
1555 }
1556
1557 /*
1558  * free storage used by a pending queue entry.
1559  */
1560
1561 void
1562 server_pending_free(Pending *pending)
1563 {
1564     free(pending->packet);
1565     free(pending);
1566     return;
1567 }
1568
1569 /*
1570  * Queue something to be handled later by this server.
1571  */
1572
1573 void
1574 server_self_queue(ZNotice_t* notice,
1575                   int auth,
1576                   struct sockaddr_in * who)
1577 {
1578     char *pack;
1579     int packlen;
1580     Code_t retval;
1581
1582     retval = ZFormatRawNotice(notice, &pack, &packlen);
1583     if (retval != ZERR_NONE) {
1584         syslog(LOG_CRIT, "srv_self_queue format: %s", error_message(retval));
1585         abort();
1586     }
1587     server_queue(me_server, packlen, pack, auth, who);
1588 }
1589
1590 /*
1591  * dump info about servers onto the fp.
1592  * assumed to be called with SIGFPE blocked
1593  * (true if called from signal handler)
1594  */
1595 void
1596 server_dump_servers(FILE *fp)
1597 {
1598     int i;
1599
1600     for (i = 0; i < nservers ; i++) {
1601         fprintf(fp, "%d:%s/%s%s\n", i, otherservers[i].addr_str,
1602                 srv_states[otherservers[i].state],
1603                 otherservers[i].dumping ? " (DUMPING)" : "");
1604     }
1605 }
1606