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