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