]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/server/server.c
39558962d36b6bf55d31fe86a3c0e3ac6cef8b33
[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()
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()
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(arg)
441     void *arg;
442 {
443     Server *which = (Server *) arg;
444     int auth = 0;
445
446 #if 0
447     zdbug((LOG_DEBUG,"srv_timo: %s", which->addr_str));
448 #endif
449     /* change state and reset if appropriate */
450     switch(which->state) {
451       case SERV_DEAD:                   /* leave him dead */
452         server_flush(which);
453         auth = 1;
454         break;
455       case SERV_UP:                     /* he's now tardy */
456         which->state = SERV_TARDY;
457         which->num_hello_sent = 0;
458         which->timeout = timo_tardy;
459         auth = 0;
460         break;
461       case SERV_TARDY:
462       case SERV_STARTING:
463         if (which->num_hello_sent >= ((which->state == SERV_TARDY) ?
464                                       H_NUM_TARDY :
465                                       H_NUM_STARTING)) {
466             /* he hasn't answered, assume DEAD */
467             which->state = SERV_DEAD;
468             which->num_hello_sent = 0;
469             which->timeout = timo_dead;
470             srv_nack_release(which);
471         }
472         auth = 0;
473         break;
474       default:
475         syslog(LOG_ERR,"Bad server state, server 0x%x\n",which);
476         abort();
477     }
478     /* now he's either TARDY, STARTING, or DEAD
479        We send a "hello," which increments the counter */
480 #if 0
481     zdbug((LOG_DEBUG, "srv %s is %s", which->addr_str,
482            srv_states[which->state]));
483 #endif
484     server_hello(which, auth);
485     /* reschedule the timer */
486     which->timer = timer_set_rel(which->timeout, server_timo, which);
487 }
488
489 /*
490  * Dispatch a notice from some other server
491  */
492
493 /*ARGSUSED*/
494 Code_t
495 server_dispatch(notice, auth, who)
496     ZNotice_t *notice;
497     int auth;
498     struct sockaddr_in *who;
499 {
500     Server *server;
501     struct sockaddr_in newwho;
502     Code_t status;
503     String *notice_class;
504
505 #if 0
506     zdbug((LOG_DEBUG, "server_dispatch"));
507 #endif
508
509     if (notice->z_kind == SERVACK) {
510         srv_nack_cancel(notice, who);
511         srv_responded(who);
512         return ZERR_NONE;
513     }
514     /* set up a who for the real origin */
515     memset(&newwho, 0, sizeof(newwho));
516     newwho.sin_family = AF_INET;
517     newwho.sin_addr.s_addr = notice->z_sender_addr.s_addr;
518     newwho.sin_port = notice->z_port;
519
520     server = server_which_server(who);
521
522     /* we can dispatch to routines safely here, since they will
523        return ZSRV_REQUEUE if appropriate.  We bounce this back
524        to the caller, and the caller will re-queue the message
525        for us to process later. */
526
527     notice_class = make_string(notice->z_class, 1);
528
529     if (realm_which_realm(&newwho))
530         status = realm_dispatch(notice, auth, &newwho, server);
531     else if (class_is_admin(notice_class)) {
532         /* admins don't get acked, else we get a packet loop */
533         /* will return  requeue if bdump request and dumping */
534         i_s_admins.val++;
535         return admin_dispatch(notice, auth, who, server);
536     } else if (class_is_control(notice_class)) {
537         status = control_dispatch(notice, auth, &newwho, server);
538         i_s_ctls.val++;
539     } else if (class_is_ulogin(notice_class)) {
540         status = ulogin_dispatch(notice, auth, &newwho, server);
541         i_s_logins.val++;
542     } else if (class_is_ulocate(notice_class)) {
543         status = ulocate_dispatch(notice, auth, &newwho, server);
544         i_s_locates.val++;
545     } else {
546         /* shouldn't come from another server */
547         syslog(LOG_WARNING, "srv_disp: pkt cls %s", notice->z_class);
548         status = ZERR_NONE;     /* XXX */
549     }
550     if (status != ZSRV_REQUEUE)
551         ack(notice, who); /* acknowledge it if processed */
552     free_string(notice_class);
553     return status;
554 }
555
556 #ifdef notdef
557 /*
558  * Register a new server (one not in our list).  This MUST be authenticated.
559  */
560
561 /*ARGSUSED*/
562 static Code_t
563 server_register(notice, auth, who)
564     ZNotice_t *notice;
565     int auth;
566     struct sockaddr_in *who;
567 {
568     Server *temp;
569     int i;
570     long timerval;
571
572     if (who->sin_port != srv_addr.sin_port) {
573 #if 0
574         zdbug((LOG_DEBUG, "srv_wrong port %d", ntohs(who->sin_port)));
575 #endif
576         return 1;
577     }
578     /* Not yet... talk to ken about authenticators */
579 #ifdef notdef
580     if (!auth) {
581 #if 0
582         zdbug((LOG_DEBUG, "srv_unauth"));
583 #endif
584         return 1;
585     }
586 #endif /* notdef */
587     /* OK, go ahead and set him up. */
588     temp = (Server *) malloc((nservers + 1) * sizeof(Server));
589     if (!temp) {
590         syslog(LOG_CRIT, "srv_reg malloc");
591         return 1;
592     }
593
594     memcpy(temp, otherservers, nservers * sizeof(Server));
595     free(otherservers);
596     otherservers = temp;
597     /* don't reschedule limbo's timer, so start i=1 */
598     for (i = 1; i < nservers; i++) {
599         if (i == me_server_idx) /* don't reset myself */
600             continue;
601         /* reschedule the timers--we moved otherservers */
602         timerval = timer_when(otherservers[i].timer);
603         timer_reset(otherservers[i].timer);
604         otherservers[i].timer = timer_set_abs(timerval, server_timo,
605                                               &otherservers[i]);
606     }
607     setup_server(&otherservers[nservers], &who->sin_addr);
608     otherservers[nservers].state = SERV_STARTING;
609     otherservers[nservers].timeout = timo_tardy;
610     otherservers[nservers].update_queue = NULL;
611     otherservers[nservers].dumping = 0;
612
613     nservers++;
614 #if 0
615     zdbug((LOG_DEBUG, "srv %s is %s", otherservers[nservers].addr_str,
616            srv_states[otherservers[nservers].state]));
617 #endif
618
619     return 0;
620 }
621 #endif
622
623 /*
624  * Tell the other servers that this client died.
625  */
626
627 void
628 server_kill_clt(client)
629     Client *client;
630 {
631     int i;
632     char buf[512], *lyst[2];
633     ZNotice_t notice;
634     ZNotice_t *pnotice; /* speed hack */
635     caddr_t pack;
636     int packlen, auth;
637     Code_t retval;
638
639     lyst[0] = inet_ntoa(client->addr.sin_addr),
640     sprintf(buf, "%d", ntohs(client->addr.sin_port));
641     lyst[1] = buf;
642
643 #if 0
644     zdbug((LOG_DEBUG, "server kill clt %s/%s", lyst[0], lyst[1]));
645 #endif
646
647     pnotice = &notice;
648
649     memset (&notice, 0, sizeof(notice));
650  
651     pnotice->z_kind = ACKED;
652
653     pnotice->z_port = srv_addr.sin_port;
654     pnotice->z_class = ZEPHYR_ADMIN_CLASS;
655     pnotice->z_class_inst = "";
656     pnotice->z_opcode = ADMIN_KILL_CLT;
657     pnotice->z_sender = myname; /* myname is the hostname */
658     pnotice->z_recipient = "";
659     pnotice->z_default_format = "";
660     pnotice->z_num_other_fields = 0;
661
662     /* XXX */
663     auth = 0;
664
665     /* don't tell limbo to flush, start at 1*/
666     for (i = 1; i < nservers; i++) {
667         if (i == me_server_idx) /* don't xmit to myself */
668             continue;
669         if (otherservers[i].state == SERV_DEAD)
670             continue;
671
672         retval = ZFormatNoticeList(pnotice, lyst, 2, &pack, &packlen,
673                                    auth ? ZAUTH : ZNOAUTH);
674         if (retval != ZERR_NONE) {
675             syslog(LOG_WARNING, "kill_clt format: %s", error_message(retval));
676             return;
677         }
678         server_forw_reliable(&otherservers[i], pack, packlen, pnotice);
679     }
680 }
681
682 /*
683  * A client has died.  remove it
684  */
685
686 static Code_t
687 kill_clt(notice, server)
688     ZNotice_t *notice;
689     Server *server;
690 {
691     struct sockaddr_in who;
692     Client *client;
693
694 #if 0
695     zdbug((LOG_DEBUG, "kill_clt"));
696 #endif
697     if (extract_addr(notice, &who) != ZERR_NONE)
698         return ZERR_NONE;       /* XXX */
699     client = client_find(&who.sin_addr, notice->z_port);
700     if (!client) {
701         syslog(LOG_NOTICE, "kill_clt: no such client (%s/%d) from %s",
702                inet_ntoa(who.sin_addr), ntohs(who.sin_port),
703                server->addr_str);
704         return ZERR_NONE;       /* XXX */
705     }
706 #if 1
707     if (zdebug || 1) {
708         syslog(LOG_DEBUG, "kill_clt clt_dereg %s/%d from %s",
709                inet_ntoa(who.sin_addr), ntohs(who.sin_port), server->addr_str);
710     }
711 #endif
712
713     /* remove the locations, too */
714     client_deregister(client, 1);
715     return ZERR_NONE;
716 }
717
718 /*
719  * extract a sockaddr_in from a message body
720  */
721
722 static Code_t
723 extract_addr(notice, who)
724     ZNotice_t *notice;
725     struct sockaddr_in *who;
726 {
727     char *cp = notice->z_message;
728
729     if (!notice->z_message_len) {
730         syslog(LOG_WARNING, "bad addr pkt");
731         return ZSRV_PKSHORT;
732     }
733     who->sin_addr.s_addr = inet_addr(notice->z_message);
734
735     cp += strlen(cp) + 1;
736     if (cp >= notice->z_message + notice->z_message_len) {
737         syslog(LOG_WARNING, "short addr pkt");
738         return ZSRV_PKSHORT;
739     }
740     who->sin_port = notice->z_port = htons((u_short) atoi(cp));
741     who->sin_family = AF_INET;
742 #if 0
743     zdbug((LOG_DEBUG,"ext %s/%d", inet_ntoa(who->sin_addr),
744            ntohs(who->sin_port)));
745 #endif
746     return ZERR_NONE;
747 }
748
749 /*
750  * Flush all data associated with the server which
751  */
752
753 static void
754 server_flush(which)
755     Server *which;
756 {
757 #if 0
758     if (zdebug)
759         syslog(LOG_DEBUG, "server_flush %s", which->addr_str);
760 #endif
761     srv_nack_release(which);
762 }
763
764 /*
765  * send a hello to which, updating the count of hello's sent
766  * Authenticate if auth is set.
767  */
768
769 static void
770 server_hello(which, auth)
771     Server *which;
772     int auth;
773 {
774     send_msg(&which->addr, ADMIN_HELLO, auth);
775     which->num_hello_sent++;
776 }
777
778 /*
779  * Handle an ADMIN message from a server
780  */
781
782 /*ARGSUSED*/
783 static Code_t
784 admin_dispatch(notice, auth, who, server)
785     ZNotice_t *notice;
786     int auth;
787     struct sockaddr_in *who;
788     Server *server;
789 {
790     char *opcode = notice->z_opcode;
791     Code_t status = ZERR_NONE;
792
793 #if 0
794     zdbug((LOG_DEBUG, "ADMIN received"));
795 #endif
796
797     if (strcmp(opcode, ADMIN_HELLO) == 0) {
798         hello_respond(who, ADJUST, auth);
799     } else if (strcmp(opcode, ADMIN_IMHERE) == 0) {
800         srv_responded(who);
801     } else if (strcmp(opcode, ADMIN_SHUTDOWN) == 0) {
802 #if 0
803         zdbug((LOG_DEBUG, "server shutdown"));
804 #endif
805         if (server) {
806             srv_nack_release(server);
807             server->state = SERV_DEAD;
808             server->timeout = timo_dead;
809             /* don't worry about the timer, it will
810                be set appropriately on the next send */
811 #if 0
812             zdbug((LOG_DEBUG, "srv %s is %s", server->addr_str,
813                    srv_states[server->state]));
814 #endif
815                 }
816     } else if (strcmp(opcode, ADMIN_BDUMP) == 0) {
817         /* Ignore a brain dump request if this is a brain dump packet
818          * or a packet being processed concurrently during a brain
819          * dump. */
820         if (bdumping || bdump_concurrent)
821             return ZERR_NONE;
822         bdump_get(notice, auth, who, server);
823     } else if (strcmp(opcode, ADMIN_KILL_CLT) == 0) {
824         status = kill_clt(notice, server);
825         if (status == ZERR_NONE)
826             ack(notice, who);
827     } else {
828         syslog(LOG_WARNING, "ADMIN unknown opcode %s",opcode);
829     }
830     return status;
831 }
832
833
834 /*
835  * Handle an ADMIN message from some random client.
836  * For now, assume it's a registration-type message from some other
837  * previously unknown server
838  */
839
840 /*ARGSUSED*/
841 Code_t
842 server_adispatch(notice, auth, who, server)
843     ZNotice_t *notice;
844     int auth;
845     struct sockaddr_in *who;
846     Server *server;
847 {
848
849     /* this had better be a HELLO message--start of acquisition
850        protocol, OR a status req packet */
851
852     if (strcmp(notice->z_opcode, ADMIN_STATUS) == 0) {
853         /* status packet */
854         send_stats(who);
855         return ZERR_NONE;
856     }
857
858 #ifdef notdef
859     syslog(LOG_INFO, "disp: new server?");
860     if (server_register(notice, auth, who) != ZERR_NONE) {
861         syslog(LOG_INFO, "new server failed");
862     } else {
863         syslog(LOG_INFO, "new server %s, %d", inet_ntoa(who->sin_addr),
864                ntohs(who->sin_port));
865         hello_respond(who, DONT_ADJUST, auth);
866     }
867 #else
868     syslog(LOG_INFO, "srv_adisp: server attempt from %s",
869            inet_ntoa(who->sin_addr));
870 #endif /* notdef */
871
872     return ZERR_NONE;
873 }
874
875 static void
876 send_stats(who)
877     struct sockaddr_in *who;
878 {
879     int i;
880     char buf[BUFSIZ];
881     char **responses;
882     int num_resp;
883     char *vers, *pkts, *upt;
884     ZRealm *realm;
885
886     int extrafields = 0;
887 #define NUM_FIXED 3                     /* 3 fixed fields, plus server info */
888                                         /* well, not really...but for
889                                            backward compatibility, we gotta
890                                            do it this way. */
891     vers = get_version();
892
893     sprintf(buf, "%d pkts", npackets);
894     pkts = strsave(buf);
895     sprintf(buf, "%d seconds operational",NOW - uptime);
896     upt = strsave(buf);
897
898 #ifdef OLD_COMPAT
899     if (old_compat_count_uloc)
900         extrafields++;
901     if (old_compat_count_ulocate)
902         extrafields++;
903     if (old_compat_count_subscr)
904         extrafields++;
905 #endif /* OLD_COMPAT */
906 #ifdef NEW_COMPAT
907     if (new_compat_count_uloc)
908         extrafields++;
909     if (new_compat_count_subscr)
910         extrafields++;
911 #endif /* NEW_COMPAT */
912     extrafields += nrealms;
913     responses = (char **) malloc((NUM_FIXED + nservers + extrafields) *
914                                  sizeof(char *));
915     responses[0] = vers;
916     responses[1] = pkts;
917     responses[2] = upt;
918
919     num_resp = NUM_FIXED;
920     /* start at 1 and ignore limbo */
921     for (i = 1; i < nservers ; i++) {
922         sprintf(buf, "%s/%s%s", otherservers[i].addr_str,
923                 srv_states[(int) otherservers[i].state],
924                 otherservers[i].dumping ? " (DUMPING)" : "");
925         responses[num_resp++] = strsave(buf);
926     }
927 #ifdef OLD_COMPAT
928     if (old_compat_count_uloc) {
929         sprintf(buf, "%d old old location requests", old_compat_count_uloc);
930         responses[num_resp++] = strsave(buf);
931     }
932     if (old_compat_count_ulocate) {
933         sprintf(buf, "%d old old loc lookup requests",
934                 old_compat_count_ulocate);
935         responses[num_resp++] = strsave(buf);
936     }
937     if (old_compat_count_subscr) {
938         sprintf(buf, "%d old old subscr requests", old_compat_count_subscr);
939         responses[num_resp++] = strsave(buf);
940     }
941 #endif /* OLD_COMPAT */
942 #ifdef NEW_COMPAT
943     if (new_compat_count_uloc) {
944         sprintf(buf, "%d new old location requests", new_compat_count_uloc);
945         responses[num_resp++] = strsave(buf);
946     }
947     if (new_compat_count_subscr) {
948         sprintf(buf, "%d new old subscr requests", new_compat_count_subscr);
949         responses[num_resp++] = strsave(buf);
950     }
951 #endif /* NEW_COMPAT */
952     for (realm = otherrealms, i = 0; i < nrealms ; i++, realm++) {
953       sprintf(buf, "%s(%s)/%s", realm->name, 
954               inet_ntoa((realm->addrs[realm->idx]).sin_addr),
955               rlm_states[(int) realm->state]);
956       responses[num_resp++] = strsave(buf);
957     }
958
959     send_msg_list(who, ADMIN_STATUS, responses, num_resp, 0);
960
961     /* Start at one; don't try to free static version string */
962     for (i = 1; i < num_resp; i++)
963         free(responses[i]);
964     free(responses);
965 }
966
967 /*
968  * Get a list of server addresses.
969 #ifdef HAVE_HESIOD
970  * This list is retrieved from Hesiod.
971 #else
972  * This list is read from a file.
973 #endif
974  * Return a pointer to an array of allocated storage.  This storage is
975  * freed by the caller.
976  */
977
978 static struct in_addr *
979 get_server_addrs(number)
980     int *number; /* RETURN */
981 {
982     int i;
983     char **server_hosts = NULL;
984     char **server_hosts_free = NULL;
985     char **cpp;
986     struct in_addr *addrs;
987     struct in_addr *addr;
988     struct hostent *hp;
989
990     server_hosts = get_server_list(list_file);
991     server_hosts_free = server_hosts;
992 #ifdef HAVE_HESIOD
993     if (!server_hosts)
994         server_hosts = hes_resolve("zephyr","sloc");
995 #endif
996     if (!server_hosts) {
997         server_hosts = get_single_server();
998         server_hosts_free = server_hosts;
999     }
1000     if (!server_hosts)
1001         return NULL;
1002     /* count up */
1003     i = 0;
1004     for (cpp = server_hosts; *cpp; cpp++)
1005         i++;
1006         
1007     addrs = (struct in_addr *) malloc(i * sizeof(struct in_addr));
1008
1009     /* Convert to in_addr's */
1010     for (cpp = server_hosts, addr = addrs, i = 0; *cpp; cpp++) {
1011         hp = gethostbyname(*cpp);
1012         if (hp) {
1013             memcpy(addr, hp->h_addr, sizeof(struct in_addr));
1014             addr++, i++;
1015         } else {
1016             syslog(LOG_WARNING, "hostname failed, %s", *cpp);
1017         }
1018     }
1019     *number = i;
1020     if (server_hosts_free)
1021       free_server_list(server_hosts_free);
1022     return addrs;
1023 }
1024
1025 static int nhosts = 0;
1026
1027 /*
1028  * read "file" to get a list of names of hosts to peer with.
1029  * The file should contain a list of host names, one per line.
1030  */
1031
1032 static char **
1033 get_server_list(file)
1034     char *file;
1035 {
1036     FILE *fp;
1037     char buf[MAXHOSTNAMELEN];
1038     char **ret_list;
1039     int nused = 0;
1040     char *newline;
1041
1042     fp = fopen(file, "r");
1043     if (!fp)
1044         return NULL;
1045     /* start with 16, realloc if necessary */
1046     nhosts = 16;
1047     ret_list = (char **) malloc(nhosts * sizeof(char *));
1048     if (!ret_list)
1049         return NULL;
1050
1051     while (fgets(buf, MAXHOSTNAMELEN, fp)) {
1052         /* nuke the newline, being careful not to overrun
1053            the buffer searching for it with strlen() */
1054         buf[MAXHOSTNAMELEN - 1] = '\0';
1055         newline = strchr(buf, '\n');
1056         if (newline)
1057             *newline = '\0';
1058
1059         if (nused + 1 >= nhosts) {
1060             /* get more pointer space if necessary */
1061             /* +1 to leave room for null pointer */
1062             ret_list = (char **) realloc(ret_list, nhosts * 2);
1063             nhosts = nhosts * 2;
1064         }
1065         ret_list[nused++] = strsave(buf);
1066     }
1067     fclose(fp);
1068     if (!nused) {
1069         free(ret_list);
1070         return NULL;
1071     }
1072     ret_list[nused] = NULL;
1073     return ret_list;
1074 }
1075
1076 static char **
1077 get_single_server()
1078 {
1079     char buf[MAXHOSTNAMELEN];
1080     char **ret_list;
1081     int nused = 0;
1082     nhosts = 2;
1083     ret_list = (char **) malloc(nhosts * sizeof(char *));
1084     if (!ret_list)
1085         return NULL;
1086     if (gethostname(buf, sizeof(buf)) < 0) {
1087         free(ret_list);
1088         return NULL;
1089     }
1090     ret_list[nused++] = strsave(buf);
1091     ret_list[nused] = NULL;
1092     return ret_list;
1093 }
1094
1095 /* 
1096  * free storage allocated by get_server_list
1097  */
1098 static void
1099 free_server_list(list)
1100     char **list;
1101 {
1102     char **orig_list = list;
1103
1104     if (!nhosts)                        /* nothing allocated */
1105         return;
1106     for (; *list; list++)
1107         free(*list);
1108     free(orig_list);
1109     return;
1110 }
1111
1112 /*
1113  * initialize the server structure for address addr, and set a timer
1114  * to go off immediately to send hello's to other servers.
1115  */
1116
1117 static void
1118 setup_server(server, addr)
1119     Server *server;
1120     struct in_addr *addr;
1121 {
1122     server->state = SERV_DEAD;
1123     server->timeout = timo_dead;
1124     server->num_hello_sent = 0;
1125     server->addr.sin_family = AF_INET;
1126     /* he listens to the same port we do */
1127     server->addr.sin_port = srv_addr.sin_port;
1128     server->addr.sin_addr = *addr;
1129     strcpy(server->addr_str, inet_ntoa(*addr));
1130     server->timer = timer_set_rel(0L, server_timo, server);
1131     server->queue = NULL;
1132     server->dumping = 0;
1133 }
1134
1135 /*
1136  * Someone sent us a hello message, respond to them.
1137  */
1138
1139 static void
1140 hello_respond(who, adj, auth)
1141     struct sockaddr_in *who;
1142     int adj;
1143     int auth;
1144 {
1145     Server *which;
1146
1147 #if 0
1148     zdbug((LOG_DEBUG, "hello from %s", inet_ntoa(who->sin_addr)));
1149 #endif
1150
1151     send_msg(who, ADMIN_IMHERE, auth);
1152     if (adj != ADJUST)
1153         return;
1154
1155     /* If we think he's down, schedule an immediate HELLO. */
1156
1157     which = server_which_server(who);
1158     if (!which)
1159         return;
1160
1161     switch (which->state) {
1162       case SERV_DEAD:
1163         /* he said hello, we thought he was dead.
1164            reschedule his hello for now. */
1165         timer_reset(which->timer);
1166         which->timer = timer_set_rel(0L, server_timo, which);
1167         break;
1168       case SERV_STARTING:
1169       case SERV_TARDY:
1170       case SERV_UP:
1171       default:
1172         break;
1173     }
1174 }    
1175
1176 /*
1177  * return the server descriptor for server at who
1178  */
1179
1180 Server *
1181 server_which_server(who)
1182     struct sockaddr_in *who;
1183 {
1184     Server *server;
1185     int i;
1186
1187     if (who->sin_port != srv_addr.sin_port)
1188         return NULL;
1189
1190     /* don't check limbo */
1191     for (server = &otherservers[1], i = 1; i < nservers; i++, server++) {
1192         if (server->addr.sin_addr.s_addr == who->sin_addr.s_addr)
1193             return server;
1194     }
1195     return NULL;
1196 }
1197
1198 /*
1199  * We received a response to a hello packet or an ack. Adjust server state
1200  * appropriately.
1201  */
1202 static void
1203 srv_responded(who)
1204     struct sockaddr_in *who;
1205 {
1206     Server *which = server_which_server(who);
1207
1208 #if 0
1209     zdbug((LOG_DEBUG, "srv_responded %s", inet_ntoa(who->sin_addr)));
1210 #endif
1211
1212     if (!which) {
1213         syslog(LOG_ERR, "hello input from non-server?!");
1214         return;
1215     }
1216
1217     switch (which->state) {
1218       case SERV_DEAD:
1219         /* he responded, we thought he was dead. mark as starting
1220            and negotiate */
1221         which->state = SERV_STARTING;
1222         which->timeout = timo_tardy;
1223         timer_reset(which->timer);
1224         which->timer = timer_set_rel(0L, server_timo, which);
1225
1226       case SERV_STARTING:
1227         /* here we negotiate and set up a braindump */
1228         if (bdump_socket < 0)
1229             bdump_offer(who);
1230         break;
1231
1232       case SERV_TARDY:
1233         which->state = SERV_UP;
1234         /* Fall through. */
1235
1236       case SERV_UP:
1237         /* reset the timer and counts */
1238         which->num_hello_sent = 0;
1239         which->timeout = timo_up;
1240         timer_reset(which->timer);
1241         which->timer = timer_set_rel(which->timeout, server_timo, which);
1242         break;
1243     }
1244 #if 0
1245     zdbug((LOG_DEBUG, "srv %s is %s", which->addr_str,
1246            srv_states[which->state]));
1247 #endif
1248 }
1249
1250 /*
1251  * Send each of the other servers a shutdown message.
1252  */
1253
1254 void
1255 server_shutdown()
1256 {
1257     int i;
1258
1259     /* don't tell limbo to go away, start at 1*/
1260     for (i = 1; i < nservers; i++)
1261         send_msg(&otherservers[i].addr, ADMIN_SHUTDOWN, 1);
1262 }
1263
1264 /*
1265  * send a message to who with admin class and opcode and clinst as specified.
1266  * auth is set if we want to send authenticated
1267  */
1268
1269 static void
1270 send_msg(who, opcode, auth)
1271     struct sockaddr_in *who;
1272     char *opcode;
1273     int auth;
1274 {
1275     ZNotice_t notice;
1276     ZNotice_t *pnotice; /* speed hack */
1277     char *pack;
1278     int packlen;
1279     Code_t retval;
1280
1281     pnotice = &notice;
1282
1283     memset (&notice, 0, sizeof(notice));
1284
1285     pnotice->z_kind = ACKED;
1286
1287     pnotice->z_port = srv_addr.sin_port;
1288     pnotice->z_class = ZEPHYR_ADMIN_CLASS;
1289     pnotice->z_class_inst = "";
1290     pnotice->z_opcode = opcode;
1291     pnotice->z_sender = myname; /* myname is the hostname */
1292     pnotice->z_recipient = "";
1293     pnotice->z_default_format = "";
1294     pnotice->z_message = NULL;
1295     pnotice->z_message_len = 0;
1296     pnotice->z_num_other_fields = 0;
1297
1298     /* XXX for now, we don't do authentication */
1299     auth = 0;
1300
1301     retval = ZFormatNotice(pnotice, &pack, &packlen, auth ? ZAUTH : ZNOAUTH);
1302     if (retval != ZERR_NONE) {
1303         syslog(LOG_WARNING, "snd_msg format: %s", error_message(retval));
1304         return;
1305     }
1306     retval = ZSetDestAddr(who);
1307     if (retval != ZERR_NONE) {
1308         syslog(LOG_WARNING, "snd_msg set addr: %s", error_message(retval));
1309         free(pack);
1310         return;
1311     }
1312     /* don't wait for ack */
1313     retval = ZSendPacket(pack, packlen, 0);
1314     if (retval != ZERR_NONE)
1315         syslog(LOG_WARNING, "snd_msg xmit: %s", error_message(retval));
1316     free(pack);
1317 }
1318
1319 /*
1320  * send a notice with a message to who with admin class and opcode and
1321  * message body as specified.
1322  * auth is set if we want to send authenticated
1323  * server_idx is -1 if we are sending to a client, or the server index
1324  *  if we are sending to a server.
1325  */
1326
1327 static void
1328 send_msg_list(who, opcode, lyst, num, auth)
1329     struct sockaddr_in *who;
1330     char *opcode;
1331     char **lyst;
1332     int num;
1333     int auth;
1334 {
1335     ZNotice_t notice;
1336     char *pack;
1337     int packlen;
1338     Code_t retval;
1339     Unacked *nacked;
1340
1341     memset (&notice, 0, sizeof(notice));
1342
1343     notice.z_kind = UNSAFE;
1344     notice.z_port = srv_addr.sin_port;
1345     notice.z_class = ZEPHYR_ADMIN_CLASS;
1346     notice.z_class_inst = "";
1347     notice.z_opcode = opcode;
1348     notice.z_sender = myname;   /* myname is the hostname */
1349     notice.z_recipient = "";
1350     notice.z_default_format = "";
1351     notice.z_message = NULL;
1352     notice.z_message_len = 0;
1353     notice.z_num_other_fields = 0;
1354
1355     /* XXX for now, we don't do authentication */
1356     auth = 0;
1357
1358     retval = ZFormatNoticeList(&notice, lyst, num, &pack, &packlen,
1359                                auth ? ZAUTH : ZNOAUTH);
1360     if (retval != ZERR_NONE) {
1361         syslog(LOG_WARNING, "snd_msg_lst format: %s", error_message(retval));
1362         return;
1363     }
1364     retval = ZSetDestAddr(who);
1365     if (retval != ZERR_NONE) {
1366         syslog(LOG_WARNING, "snd_msg_lst set addr: %s", error_message(retval));
1367         free(pack);
1368         return;
1369     }
1370     xmit_frag(&notice, pack, packlen, 0);
1371     free(pack);
1372 }
1373
1374 /*
1375  * Forward the notice to the other servers
1376  */
1377 /*ARGSUSED*/
1378 void
1379 server_forward(notice, auth, who)
1380     ZNotice_t *notice;
1381     int auth;
1382     struct sockaddr_in *who;
1383 {
1384     int i;
1385     caddr_t pack;
1386     int packlen;
1387     Code_t retval;
1388
1389 #if 0
1390     zdbug((LOG_DEBUG, "srv_forw"));
1391 #endif
1392     /* don't send to limbo */
1393     for (i = 1; i < nservers; i++) {
1394         if (i == me_server_idx) /* don't xmit to myself */
1395             continue;
1396         if (otherservers[i].state == SERV_DEAD &&
1397             otherservers[i].dumping == 0) {
1398             /* if we are dumping to him, we want to
1399                queue it, even if he's dead */
1400             continue;
1401         }
1402
1403         pack = malloc(sizeof(ZPacket_t));
1404         if (!pack) {
1405             syslog(LOG_CRIT, "srv_fwd malloc");
1406             abort();
1407         }
1408         retval = ZNewFormatSmallRawNotice(notice, pack, &packlen);
1409         if (retval != ZERR_NONE) {
1410             syslog(LOG_WARNING, "srv_fwd format: %s", error_message(retval));
1411             continue;
1412         }
1413         if (otherservers[i].dumping) {
1414             server_queue(&otherservers[i], packlen, pack, auth, who);
1415             continue;
1416         }
1417         server_forw_reliable(&otherservers[i], pack, packlen, notice);
1418     }
1419 }
1420
1421 static void
1422 server_forw_reliable(server, pack, packlen, notice)
1423     Server *server;
1424     caddr_t pack;
1425     int packlen;
1426     ZNotice_t *notice;
1427 {
1428     Code_t retval;
1429     Unacked *nacked;
1430     int hashval;
1431
1432     retval = ZSetDestAddr(&server->addr);
1433     if (retval != ZERR_NONE) {
1434         syslog(LOG_WARNING, "srv_fwd_rel set addr: %s", error_message(retval));
1435         free(pack);
1436         return;
1437     }
1438     retval = ZSendPacket(pack, packlen, 0);
1439     if (retval != ZERR_NONE) {
1440         syslog(LOG_WARNING, "srv_fwd xmit: %s", error_message(retval));
1441         free(pack);
1442         return;
1443     }                   
1444     /* now we've sent it, mark it as not ack'ed */
1445                 
1446     nacked = (Unacked *) malloc(sizeof(Unacked));
1447     if (!nacked) {
1448         /* no space: just punt */
1449         syslog(LOG_ERR, "srv_forw_rel nack malloc");
1450         free(pack);
1451         return;
1452     }
1453
1454     nacked->client = NULL;
1455     nacked->rexmits = 0;
1456     nacked->packet = pack;
1457     nacked->dest.srv_idx = server - otherservers;
1458     nacked->packsz = packlen;
1459     nacked->uid = notice->z_uid;
1460     nacked->timer = timer_set_rel(rexmit_times[0], srv_rexmit, nacked);
1461     hashval = SRV_NACKTAB_HASHVAL(nacked->dest.srv_idx, nacked->uid);
1462     LIST_INSERT(&srv_nacktab[hashval], nacked);
1463 }
1464
1465 /*
1466  * send the queued message for the server.
1467  */
1468
1469 void
1470 server_send_queue(server)
1471     Server *server;
1472 {
1473     Pending *pending;
1474     ZNotice_t notice;
1475     Code_t status;
1476
1477     while (server->queue) {
1478         pending = server_dequeue(server);
1479         status = ZParseNotice(pending->packet, pending->len, &notice);
1480         if (status != ZERR_NONE) {
1481             syslog(LOG_ERR, "ssq bad notice parse (%s): %s",
1482                    inet_ntoa(pending->who.sin_addr), error_message(status));
1483         } else {
1484             server_forw_reliable(server, pending->packet, pending->len,
1485                                  &notice);
1486             free(pending);
1487             /* ACK handling routines will free the packet */
1488         }
1489     }
1490 }
1491
1492 /*
1493  * a server has acknowledged a message we sent to him; remove it from
1494  * server unacked queue
1495  */
1496
1497 static void
1498 srv_nack_cancel(notice, who)
1499     ZNotice_t *notice;
1500     struct sockaddr_in *who;
1501 {
1502     Server *server = server_which_server(who);
1503     Unacked *nacked;
1504     int hashval;
1505
1506     if (!server) {
1507         syslog(LOG_ERR, "non-server ack?");
1508         return;
1509     }
1510     hashval = SRV_NACKTAB_HASHVAL(server - otherservers, notice->z_uid);
1511     for (nacked = srv_nacktab[hashval]; nacked; nacked = nacked->next) {
1512         if (nacked->dest.srv_idx == server - otherservers
1513             && ZCompareUID(&nacked->uid, &notice->z_uid)) {
1514             timer_reset(nacked->timer);
1515             free(nacked->packet);
1516             LIST_DELETE(nacked);
1517             free(nacked);
1518             return;
1519         }
1520     }
1521 #if 0
1522     zdbug((LOG_DEBUG, "srv_nack not found"));
1523 #endif
1524 }
1525
1526 /*
1527  * retransmit a message to another server
1528  */
1529
1530 static void
1531 srv_rexmit(arg)
1532     void *arg;
1533 {
1534     Unacked *packet = (Unacked *) arg;
1535     Code_t retval;
1536     /* retransmit the packet */
1537         
1538 #if 0
1539     zdbug((LOG_DEBUG,"srv_rexmit to %s/%d",
1540            otherservers[packet->dest.srv_idx].addr_str,
1541            ntohs(otherservers[packet->dest.srv_idx].addr.sin_port)));
1542 #endif
1543     if (otherservers[packet->dest.srv_idx].state == SERV_DEAD) {
1544 #if 0
1545         zdbug((LOG_DEBUG, "cancelling send to dead server"));
1546 #endif
1547         LIST_DELETE(packet);
1548         free(packet->packet);
1549         srv_nack_release(&otherservers[packet->dest.srv_idx]);
1550         free(packet);
1551         return;
1552     }
1553     retval = ZSetDestAddr(&otherservers[packet->dest.srv_idx].addr);
1554     if (retval != ZERR_NONE) {
1555         syslog(LOG_WARNING, "srv_rexmit set addr: %s", error_message(retval));
1556     } else {
1557         retval = ZSendPacket(packet->packet, packet->packsz, 0);
1558         if (retval != ZERR_NONE)
1559             syslog(LOG_WARNING, "srv_rexmit xmit: %s",
1560                    error_message(retval));
1561     }
1562
1563     /* reset the timer */
1564     if (rexmit_times[packet->rexmits + 1] != -1)
1565         packet->rexmits++;
1566     packet->timer = timer_set_rel(rexmit_times[packet->rexmits], srv_rexmit,
1567                                   packet);
1568 }
1569
1570 /*
1571  * Clean up the not-yet-acked queue and release anything destined
1572  * to the server.
1573  */
1574
1575 static void
1576 srv_nack_release(server)
1577     Server *server;
1578 {
1579     int i;
1580     Unacked *nacked, *next;
1581
1582     for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) {
1583         for (nacked = srv_nacktab[i]; nacked; nacked = next) {
1584             next = nacked->next;
1585             if (nacked->dest.srv_idx == server - otherservers) {
1586                 timer_reset(nacked->timer);
1587                 LIST_DELETE(nacked);
1588                 free(nacked->packet);
1589                 free(nacked);
1590             }
1591         }
1592     }
1593 }
1594
1595 /*
1596  * Adjust indices of not-yet-acked packets sent to other servers to
1597  * continue to refer to the correct server.
1598  */
1599
1600 static void
1601 srv_nack_renumber (new_idx)
1602     int *new_idx;
1603 {
1604     /* XXX release any private queue for this server */
1605     Unacked *nacked;
1606     int idx, i;
1607
1608     /* search the not-yet-acked list for anything destined to 'from', and
1609        change the index to 'to'. */
1610     for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) {
1611         for (nacked = srv_nacktab[i]; nacked; nacked = nacked->next) {
1612             idx = new_idx[nacked->dest.srv_idx];
1613             if (idx < 0) {
1614                 syslog(LOG_ERR, "srv_nack_renumber error: [%d]=%d",
1615                        nacked->dest.srv_idx, idx);
1616                 idx = 0;
1617             }
1618             nacked->dest.srv_idx = idx;
1619         }
1620     }
1621 }
1622
1623 /*
1624  * Queue this notice to be transmitted to the server when it is ready.
1625  */
1626 static void
1627 server_queue(server, len, pack, auth, who)
1628     Server *server;
1629     int len;
1630     void *pack;
1631     int auth;
1632     struct sockaddr_in *who;
1633 {
1634     Pending *pending;
1635
1636     pending = (Pending *) malloc(sizeof(Pending));
1637     if (!pending) {
1638         syslog(LOG_CRIT, "update_queue malloc");
1639         abort();
1640     }
1641     pending->packet = pack;
1642     pending->len = len;
1643     pending->auth = auth;
1644     pending->who = *who;
1645     pending->next = NULL;
1646
1647     /* put it on the end of the list */
1648     if (server->queue)
1649         server->queue_last->next = pending;
1650     else
1651         server->queue = server->queue_last = pending;
1652 }
1653
1654 /*
1655  * Pull a notice off the hold queue.
1656  */
1657
1658 Pending *
1659 server_dequeue(server)
1660     Server *server;
1661 {
1662     Pending *pending;
1663         
1664     if (!server->queue)
1665         return NULL;
1666     pending = server->queue;
1667     server->queue = pending->next;
1668     return pending;
1669 }
1670
1671 /*
1672  * free storage used by a pending queue entry.
1673  */
1674
1675 void
1676 server_pending_free(pending)
1677     Pending *pending;
1678 {
1679     free(pending->packet);
1680     free(pending);
1681     return;
1682 }
1683
1684 /*
1685  * Queue something to be handled later by this server.
1686  */
1687
1688 void
1689 server_self_queue(notice, auth, who)
1690     ZNotice_t* notice;
1691     int auth;
1692     struct sockaddr_in * who;
1693 {
1694     char *pack;
1695     int packlen;
1696     Code_t retval;
1697
1698     retval = ZFormatRawNotice(notice, &pack, &packlen);
1699     if (retval != ZERR_NONE) {
1700         syslog(LOG_CRIT, "srv_self_queue format: %s", error_message(retval));
1701         abort();
1702     }
1703     server_queue(me_server, packlen, pack, auth, who);
1704 }
1705
1706 /*
1707  * dump info about servers onto the fp.
1708  * assumed to be called with SIGFPE blocked
1709  * (true if called from signal handler)
1710  */
1711 void
1712 server_dump_servers(fp)
1713     FILE *fp;
1714 {
1715     int i;
1716
1717     for (i = 0; i < nservers ; i++) {
1718         fprintf(fp, "%d:%s/%s%s\n", i, otherservers[i].addr_str,
1719                 srv_states[otherservers[i].state],
1720                 otherservers[i].dumping ? " (DUMPING)" : "");
1721     }
1722 }
1723