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