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