viced-deadlock-20060620
[openafs.git] / src / viced / host.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  *
9  * Portions Copyright (c) 2006 Sine Nomine Associates
10  */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 RCSID
16     ("$Header$");
17
18 #include <stdio.h>
19 #include <errno.h>
20 #ifdef AFS_NT40_ENV
21 #include <fcntl.h>
22 #include <winsock2.h>
23 #else
24 #include <sys/file.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #endif
28
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #else
32 #ifdef HAVE_STRINGS_H
33 #include <strings.h>
34 #endif
35 #endif
36
37 #include <afs/stds.h>
38 #include <rx/xdr.h>
39 #include <afs/assert.h>
40 #include <lwp.h>
41 #include <lock.h>
42 #include <afs/afsint.h>
43 #include <afs/rxgen_consts.h>
44 #include <afs/nfs.h>
45 #include <afs/errors.h>
46 #include <afs/ihandle.h>
47 #include <afs/vnode.h>
48 #include <afs/volume.h>
49 #ifdef AFS_ATHENA_STDENV
50 #include <krb.h>
51 #endif
52 #include <afs/acl.h>
53 #include <afs/ptclient.h>
54 #include <afs/ptuser.h>
55 #include <afs/prs_fs.h>
56 #include <afs/auth.h>
57 #include <afs/afsutil.h>
58 #include <rx/rx.h>
59 #include <afs/cellconfig.h>
60 #include <stdlib.h>
61 #include "viced_prototypes.h"
62 #include "viced.h"
63 #include "host.h"
64 #include "callback.h"
65 #ifdef AFS_DEMAND_ATTACH_FS
66 #include "../util/afsutil_prototypes.h"
67 #include "../tviced/serialize_state.h"
68 #endif /* AFS_DEMAND_ATTACH_FS */
69
70 #ifdef AFS_PTHREAD_ENV
71 pthread_mutex_t host_glock_mutex;
72 #endif /* AFS_PTHREAD_ENV */
73
74 extern int Console;
75 extern int CurrentConnections;
76 extern int SystemId;
77 extern int AnonymousID;
78 extern prlist AnonCPS;
79 extern int LogLevel;
80 extern struct afsconf_dir *confDir;     /* config dir object */
81 extern int lwps;                /* the max number of server threads */
82 extern afsUUID FS_HostUUID;
83
84 int CEs = 0;                    /* active clients */
85 int CEBlocks = 0;               /* number of blocks of CEs */
86 struct client *CEFree = 0;      /* first free client */
87 struct host *hostList = 0;      /* linked list of all hosts */
88 int hostCount = 0;              /* number of hosts in hostList */
89 int rxcon_ident_key;
90 int rxcon_client_key;
91
92 static struct rx_securityClass *sc = NULL;
93
94 static void h_SetupCallbackConn_r(struct host * host);
95 static void h_AddHostToHashTable_r(afs_uint32 addr, afs_uint16 port, struct host * host);
96 static void h_AddHostToUuidHashTable_r(afsUUID * uuid, struct host * host);
97 static int h_DeleteHostFromHashTableByAddr_r(afs_uint32 addr, afs_uint16 port, struct host *host);
98
99 #define CESPERBLOCK 73
100 struct CEBlock {                /* block of CESPERBLOCK file entries */
101     struct client entry[CESPERBLOCK];
102 };
103
104 static void h_TossStuff_r(register struct host *host);
105 static int hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host);
106
107 /*
108  * Make sure the subnet macros have been defined.
109  */
110 #ifndef IN_SUBNETA
111 #define IN_SUBNETA(i)           ((((afs_int32)(i))&0x80800000)==0x00800000)
112 #endif
113
114 #ifndef IN_CLASSA_SUBNET
115 #define IN_CLASSA_SUBNET        0xffff0000
116 #endif
117
118 #ifndef IN_SUBNETB
119 #define IN_SUBNETB(i)           ((((afs_int32)(i))&0xc0008000)==0x80008000)
120 #endif
121
122 #ifndef IN_CLASSB_SUBNET
123 #define IN_CLASSB_SUBNET        0xffffff00
124 #endif
125
126
127 /* get a new block of CEs and chain it on CEFree */
128 static void
129 GetCEBlock()
130 {
131     register struct CEBlock *block;
132     register int i;
133
134     block = (struct CEBlock *)malloc(sizeof(struct CEBlock));
135     if (!block) {
136         ViceLog(0, ("Failed malloc in GetCEBlock\n"));
137         ShutDownAndCore(PANIC);
138     }
139
140     for (i = 0; i < (CESPERBLOCK - 1); i++) {
141         Lock_Init(&block->entry[i].lock);
142         block->entry[i].next = &(block->entry[i + 1]);
143     }
144     block->entry[CESPERBLOCK - 1].next = 0;
145     Lock_Init(&block->entry[CESPERBLOCK - 1].lock);
146     CEFree = (struct client *)block;
147     CEBlocks++;
148
149 }                               /*GetCEBlock */
150
151
152 /* get the next available CE */
153 static struct client *
154 GetCE()
155 {
156     register struct client *entry;
157
158     if (CEFree == 0)
159         GetCEBlock();
160     if (CEFree == 0) {
161         ViceLog(0, ("CEFree NULL in GetCE\n"));
162         ShutDownAndCore(PANIC);
163     }
164
165     entry = CEFree;
166     CEFree = entry->next;
167     CEs++;
168     memset((char *)entry, 0, CLIENT_TO_ZERO(entry));
169     return (entry);
170
171 }                               /*GetCE */
172
173
174 /* return an entry to the free list */
175 static void
176 FreeCE(register struct client *entry)
177 {
178     entry->VenusEpoch = 0;
179     entry->sid = 0;
180     entry->next = CEFree;
181     CEFree = entry;
182     CEs--;
183
184 }                               /*FreeCE */
185
186 /*
187  * The HTs and HTBlocks variables were formerly static, but they are
188  * now referenced elsewhere in the FileServer.
189  */
190 int HTs = 0;                    /* active file entries */
191 int HTBlocks = 0;               /* number of blocks of HTs */
192 static struct host *HTFree = 0; /* first free file entry */
193
194 /*
195  * Hash tables of host pointers. We need two tables, one
196  * to map IP addresses onto host pointers, and another
197  * to map host UUIDs onto host pointers.
198  */
199 static struct h_hashChain *hostHashTable[h_HASHENTRIES];
200 static struct h_hashChain *hostUuidHashTable[h_HASHENTRIES];
201 #define h_HashIndex(hostip) ((hostip) & (h_HASHENTRIES-1))
202 #define h_UuidHashIndex(uuidp) (((int)(afs_uuid_hash(uuidp))) & (h_HASHENTRIES-1))
203
204 struct HTBlock {                /* block of HTSPERBLOCK file entries */
205     struct host entry[h_HTSPERBLOCK];
206 };
207
208
209 /* get a new block of HTs and chain it on HTFree */
210 static void
211 GetHTBlock()
212 {
213     register struct HTBlock *block;
214     register int i;
215     static int index = 0;
216
217     if (HTBlocks == h_MAXHOSTTABLES) {
218         ViceLog(0, ("h_MAXHOSTTABLES reached\n"));
219         ShutDownAndCore(PANIC);
220     }
221
222     block = (struct HTBlock *)malloc(sizeof(struct HTBlock));
223     if (!block) {
224         ViceLog(0, ("Failed malloc in GetHTBlock\n"));
225         ShutDownAndCore(PANIC);
226     }
227 #ifdef AFS_PTHREAD_ENV
228     for (i = 0; i < (h_HTSPERBLOCK); i++)
229         assert(pthread_cond_init(&block->entry[i].cond, NULL) == 0);
230 #endif /* AFS_PTHREAD_ENV */
231     for (i = 0; i < (h_HTSPERBLOCK); i++)
232         Lock_Init(&block->entry[i].lock);
233     for (i = 0; i < (h_HTSPERBLOCK - 1); i++)
234         block->entry[i].next = &(block->entry[i + 1]);
235     for (i = 0; i < (h_HTSPERBLOCK); i++)
236         block->entry[i].index = index++;
237     block->entry[h_HTSPERBLOCK - 1].next = 0;
238     HTFree = (struct host *)block;
239     hosttableptrs[HTBlocks++] = block->entry;
240
241 }                               /*GetHTBlock */
242
243
244 /* get the next available HT */
245 static struct host *
246 GetHT()
247 {
248     register struct host *entry;
249
250     if (HTFree == NULL)
251         GetHTBlock();
252     assert(HTFree != NULL);
253     entry = HTFree;
254     HTFree = entry->next;
255     HTs++;
256     memset((char *)entry, 0, HOST_TO_ZERO(entry));
257     return (entry);
258
259 }                               /*GetHT */
260
261
262 /* return an entry to the free list */
263 static void
264 FreeHT(register struct host *entry)
265 {
266     entry->next = HTFree;
267     HTFree = entry;
268     HTs--;
269
270 }                               /*FreeHT */
271
272
273 static short consolePort = 0;
274
275 int
276 h_Release(register struct host *host)
277 {
278     H_LOCK;
279     h_Release_r(host);
280     H_UNLOCK;
281     return 0;
282 }
283
284 /**
285  * If this thread does not have a hold on this host AND
286  * if other threads also dont have any holds on this host AND
287  * If either the HOSTDELETED or CLIENTDELETED flags are set
288  * then toss the host
289  */
290 int
291 h_Release_r(register struct host *host)
292 {
293
294     if (!((host)->holds[h_holdSlot()] & ~h_holdbit())) {
295         if (!h_OtherHolds_r(host)) {
296             /* must avoid masking this until after h_OtherHolds_r runs
297              * but it should be run before h_TossStuff_r */
298             (host)->holds[h_holdSlot()] &= ~h_holdbit();
299             if ((host->hostFlags & HOSTDELETED)
300                 || (host->hostFlags & CLIENTDELETED)) {
301                 h_TossStuff_r(host);
302             }
303         } else
304             (host)->holds[h_holdSlot()] &= ~h_holdbit();
305     } else
306         (host)->holds[h_holdSlot()] &= ~h_holdbit();
307
308     return 0;
309 }
310
311 int
312 h_OtherHolds_r(register struct host *host)
313 {
314     register int i, bit, slot;
315     bit = h_holdbit();
316     slot = h_holdSlot();
317     for (i = 0; i < h_maxSlots; i++) {
318         if (host->holds[i] != ((i == slot) ? bit : 0)) {
319             return 1;
320         }
321     }
322     return 0;
323 }
324
325 int
326 h_Lock_r(register struct host *host)
327 {
328     H_UNLOCK;
329     h_Lock(host);
330     H_LOCK;
331     return 0;
332 }
333
334 /**
335   * Non-blocking lock
336   * returns 1 if already locked
337   * else returns locks and returns 0
338   */
339
340 int
341 h_NBLock_r(register struct host *host)
342 {
343     struct Lock *hostLock = &host->lock;
344     int locked = 0;
345
346     H_UNLOCK;
347     LOCK_LOCK(hostLock);
348     if (!(hostLock->excl_locked) && !(hostLock->readers_reading))
349         hostLock->excl_locked = WRITE_LOCK;
350     else
351         locked = 1;
352
353     LOCK_UNLOCK(hostLock);
354     H_LOCK;
355     if (locked)
356         return 1;
357     else
358         return 0;
359 }
360
361
362 #if FS_STATS_DETAILED
363 /*------------------------------------------------------------------------
364  * PRIVATE h_AddrInSameNetwork
365  *
366  * Description:
367  *      Given a target IP address and a candidate IP address (both
368  *      in host byte order), return a non-zero value (1) if the
369  *      candidate address is in a different network from the target
370  *      address.
371  *
372  * Arguments:
373  *      a_targetAddr       : Target address.
374  *      a_candAddr         : Candidate address.
375  *
376  * Returns:
377  *      1 if the candidate address is in the same net as the target,
378  *      0 otherwise.
379  *
380  * Environment:
381  *      The target and candidate addresses are both in host byte
382  *      order, NOT network byte order, when passed in.  We return
383  *      our value as a character, since that's the type of field in
384  *      the host structure, where this info will be stored.
385  *
386  * Side Effects:
387  *      As advertised.
388  *------------------------------------------------------------------------*/
389
390 static char
391 h_AddrInSameNetwork(afs_uint32 a_targetAddr, afs_uint32 a_candAddr)
392 {                               /*h_AddrInSameNetwork */
393
394     afs_uint32 targetNet;
395     afs_uint32 candNet;
396
397     /*
398      * Pull out the network and subnetwork numbers from the target
399      * and candidate addresses.  We can short-circuit this whole
400      * affair if the target and candidate addresses are not of the
401      * same class.
402      */
403     if (IN_CLASSA(a_targetAddr)) {
404         if (!(IN_CLASSA(a_candAddr))) {
405             return (0);
406         }
407         targetNet = a_targetAddr & IN_CLASSA_NET;
408         candNet = a_candAddr & IN_CLASSA_NET;
409     } else if (IN_CLASSB(a_targetAddr)) {
410         if (!(IN_CLASSB(a_candAddr))) {
411             return (0);
412         }
413         targetNet = a_targetAddr & IN_CLASSB_NET;
414         candNet = a_candAddr & IN_CLASSB_NET;
415     } /*Class B target */
416     else if (IN_CLASSC(a_targetAddr)) {
417         if (!(IN_CLASSC(a_candAddr))) {
418             return (0);
419         }
420         targetNet = a_targetAddr & IN_CLASSC_NET;
421         candNet = a_candAddr & IN_CLASSC_NET;
422     } /*Class C target */
423     else {
424         targetNet = a_targetAddr;
425         candNet = a_candAddr;
426     }                           /*Class D address */
427
428     /*
429      * Now, simply compare the extracted net values for the two addresses
430      * (which at this point are known to be of the same class)
431      */
432     if (targetNet == candNet)
433         return (1);
434     else
435         return (0);
436
437 }                               /*h_AddrInSameNetwork */
438 #endif /* FS_STATS_DETAILED */
439
440
441 /* Assumptions: called with held host */
442 void
443 h_gethostcps_r(register struct host *host, register afs_int32 now)
444 {
445     register int code;
446     int slept = 0;
447
448     /* wait if somebody else is already doing the getCPS call */
449     while (host->hostFlags & HCPS_INPROGRESS) {
450         slept = 1;              /* I did sleep */
451         host->hostFlags |= HCPS_WAITING;        /* I am sleeping now */
452 #ifdef AFS_PTHREAD_ENV
453         pthread_cond_wait(&host->cond, &host_glock_mutex);
454 #else /* AFS_PTHREAD_ENV */
455         if ((code = LWP_WaitProcess(&(host->hostFlags))) != LWP_SUCCESS)
456             ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
457 #endif /* AFS_PTHREAD_ENV */
458     }
459
460
461     host->hostFlags |= HCPS_INPROGRESS; /* mark as CPSCall in progress */
462     if (host->hcps.prlist_val)
463         free(host->hcps.prlist_val);    /* this is for hostaclRefresh */
464     host->hcps.prlist_val = NULL;
465     host->hcps.prlist_len = 0;
466     host->cpsCall = slept ? (FT_ApproxTime()) : (now);
467
468     H_UNLOCK;
469     code = pr_GetHostCPS(ntohl(host->host), &host->hcps);
470     H_LOCK;
471     if (code) {
472         /*
473          * Although ubik_Call (called by pr_GetHostCPS) traverses thru all protection servers
474          * and reevaluates things if no sync server or quorum is found we could still end up
475          * with one of these errors. In such case we would like to reevaluate the rpc call to
476          * find if there's cps for this guy. We treat other errors (except network failures
477          * ones - i.e. code < 0) as an indication that there is no CPS for this host. Ideally
478          * we could like to deal this problem the other way around (i.e. if code == NOCPS 
479          * ignore else retry next time) but the problem is that there're other errors (i.e.
480          * EPERM) for which we don't want to retry and we don't know the whole code list!
481          */
482         if (code < 0 || code == UNOQUORUM || code == UNOTSYNC) {
483             /* 
484              * We would have preferred to use a while loop and try again since ops in protected
485              * acls for this host will fail now but they'll be reevaluated on any subsequent
486              * call. The attempt to wait for a quorum/sync site or network error won't work
487              * since this problems really should only occurs during a complete fileserver 
488              * restart. Since the fileserver will start before the ptservers (and thus before
489              * quorums are complete) clients will be utilizing all the fileserver's lwps!!
490              */
491             host->hcpsfailed = 1;
492             ViceLog(0,
493                     ("Warning:  GetHostCPS failed (%d) for %x; will retry\n",
494                      code, host->host));
495         } else {
496             host->hcpsfailed = 0;
497             ViceLog(1,
498                     ("gethost:  GetHostCPS failed (%d) for %x; ignored\n",
499                      code, host->host));
500         }
501         if (host->hcps.prlist_val)
502             free(host->hcps.prlist_val);
503         host->hcps.prlist_val = NULL;
504         host->hcps.prlist_len = 0;      /* Make sure it's zero */
505     } else
506         host->hcpsfailed = 0;
507
508     host->hostFlags &= ~HCPS_INPROGRESS;
509     /* signal all who are waiting */
510     if (host->hostFlags & HCPS_WAITING) {       /* somebody is waiting */
511         host->hostFlags &= ~HCPS_WAITING;
512 #ifdef AFS_PTHREAD_ENV
513         assert(pthread_cond_broadcast(&host->cond) == 0);
514 #else /* AFS_PTHREAD_ENV */
515         if ((code = LWP_NoYieldSignal(&(host->hostFlags))) != LWP_SUCCESS)
516             ViceLog(0, ("LWP_NoYieldSignal returns %d\n", code));
517 #endif /* AFS_PTHREAD_ENV */
518     }
519 }
520
521 /* args in net byte order */
522 void
523 h_flushhostcps(register afs_uint32 hostaddr, register afs_uint16 hport)
524 {
525     register struct host *host;
526     int held = 0;
527
528     H_LOCK;
529     host = h_Lookup_r(hostaddr, hport, &held);
530     if (host) {
531         host->hcpsfailed = 1;
532         if (!held)
533             h_Release_r(host);
534     }
535     H_UNLOCK;
536     return;
537 }
538
539
540 /*
541  * Allocate a host.  It will be identified by the peer (ip,port) info in the
542  * rx connection provided.  The host is returned held and locked
543  */
544 #define DEF_ROPCONS 2115
545
546 struct host *
547 h_Alloc_r(register struct rx_connection *r_con)
548 {
549     struct servent *serverentry;
550     struct host *host;
551     afs_int32 now;
552 #if FS_STATS_DETAILED
553     afs_uint32 newHostAddr_HBO; /*New host IP addr, in host byte order */
554 #endif /* FS_STATS_DETAILED */
555
556     host = GetHT();
557
558     host->host = rxr_HostOf(r_con);
559     host->port = rxr_PortOf(r_con);
560
561     h_AddHostToHashTable_r(host->host, host->port, host);
562
563     if (consolePort == 0) {     /* find the portal number for console */
564 #if     defined(AFS_OSF_ENV)
565         serverentry = getservbyname("ropcons", "");
566 #else
567         serverentry = getservbyname("ropcons", 0);
568 #endif
569         if (serverentry)
570             consolePort = serverentry->s_port;
571         else
572             consolePort = htons(DEF_ROPCONS);   /* Use a default */
573     }
574     if (host->port == consolePort)
575         host->Console = 1;
576     /* Make a callback channel even for the console, on the off chance that it
577      * makes a request that causes a break call back.  It shouldn't. */
578     h_SetupCallbackConn_r(host);
579     now = host->LastCall = host->cpsCall = host->ActiveCall = FT_ApproxTime();
580     host->hostFlags = 0;
581     host->hcps.prlist_val = NULL;
582     host->hcps.prlist_len = 0;
583     host->interface = NULL;
584 #ifdef undef
585     host->hcpsfailed = 0;       /* save cycles */
586     h_gethostcps(host);         /* do this under host hold/lock */
587 #endif
588     host->FirstClient = NULL;
589     h_Hold_r(host);
590     h_Lock_r(host);
591     h_InsertList_r(host);       /* update global host List */
592 #if FS_STATS_DETAILED
593     /*
594      * Compare the new host's IP address (in host byte order) with ours
595      * (the File Server's), remembering if they are in the same network.
596      */
597     newHostAddr_HBO = (afs_uint32) ntohl(host->host);
598     host->InSameNetwork =
599         h_AddrInSameNetwork(FS_HostAddr_HBO, newHostAddr_HBO);
600 #endif /* FS_STATS_DETAILED */
601     return host;
602
603 }                               /*h_Alloc_r */
604
605
606
607 /* Make a callback channel even for the console, on the off chance that it
608  * makes a request that causes a break call back.  It shouldn't. */
609 static void
610 h_SetupCallbackConn_r(struct host * host)
611 {
612     if (!sc)
613         sc = rxnull_NewClientSecurityObject();
614     host->callback_rxcon =
615         rx_NewConnection(host->host, host->port, 1, sc, 0);
616     rx_SetConnDeadTime(host->callback_rxcon, 50);
617     rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
618 }
619
620 /* Lookup a host given an IP address and UDP port number. */
621 /* hostaddr and hport are in network order */
622 /* Note: host should be released by caller if 0 == *heldp and non-null */
623 /* hostaddr and hport are in network order */
624 struct host *
625 h_Lookup_r(afs_uint32 haddr, afs_uint16 hport, int *heldp)
626 {
627     afs_int32 now;
628     struct host *host = 0;
629     struct h_hashChain *chain;
630     int index = h_HashIndex(haddr);
631     extern int hostaclRefresh;
632
633   restart:
634     for (chain = hostHashTable[index]; chain; chain = chain->next) {
635         host = chain->hostPtr;
636         assert(host);
637         if (!(host->hostFlags & HOSTDELETED) && chain->addr == haddr
638             && chain->port == hport) {
639             *heldp = h_Held_r(host);
640             if (!*heldp)
641                 h_Hold_r(host);
642             h_Lock_r(host);
643             if (host->hostFlags & HOSTDELETED) {
644                 h_Unlock_r(host);
645                 if (!*heldp)
646                     h_Release_r(host);
647                 goto restart;
648             }
649             h_Unlock_r(host);
650             now = FT_ApproxTime();      /* always evaluate "now" */
651             if (host->hcpsfailed || (host->cpsCall + hostaclRefresh < now)) {
652                 /*
653                  * Every hostaclRefresh period (def 2 hrs) get the new
654                  * membership list for the host.  Note this could be the
655                  * first time that the host is added to a group.  Also
656                  * here we also retry on previous legitimate hcps failures.
657                  *
658                  * If we get here we still have a host hold.
659                  */
660                 h_gethostcps_r(host, now);
661             }
662             break;
663         }
664         host = NULL;
665     }
666     return host;
667
668 }                               /*h_Lookup */
669
670 /* Lookup a host given its UUID. */
671 struct host *
672 h_LookupUuid_r(afsUUID * uuidp)
673 {
674     struct host *host = 0;
675     struct h_hashChain *chain;
676     int index = h_UuidHashIndex(uuidp);
677
678     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
679         host = chain->hostPtr;
680         assert(host);
681         if (!(host->hostFlags & HOSTDELETED) && host->interface
682             && afs_uuid_equal(&host->interface->uuid, uuidp)) {
683             break;
684         }
685         host = NULL;
686     }
687     return host;
688
689 }                               /*h_Lookup */
690
691
692 /*
693  * h_Hold_r: Establish a hold by the current LWP on this host--the host
694  * or its clients will not be physically deleted until all holds have
695  * been released.
696  * NOTE: h_Hold_r is a macro defined in host.h.
697  */
698
699 /* h_TossStuff_r:  Toss anything in the host structure (the host or
700  * clients marked for deletion.  Called from h_Release_r ONLY.
701  * To be called, there must be no holds, and either host->deleted
702  * or host->clientDeleted must be set.
703  */
704 static void
705 h_TossStuff_r(register struct host *host)
706 {
707     register struct client **cp, *client;
708     int i;
709
710     /* if somebody still has this host held */
711     for (i = 0; (i < h_maxSlots) && (!(host)->holds[i]); i++);
712     if (i != h_maxSlots)
713         return;
714
715     /* if somebody still has this host locked */
716     if (h_NBLock_r(host) != 0) {
717         char hoststr[16];
718         ViceLog(0,
719                 ("Warning:  h_TossStuff_r failed; Host %s:%d was locked.\n",
720                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
721         return;
722     } else {
723         h_Unlock_r(host);
724     }
725
726     /* ASSUMPTION: rxi_FreeConnection() does not yield */
727     for (cp = &host->FirstClient; (client = *cp);) {
728         if ((host->hostFlags & HOSTDELETED) || client->deleted) {
729             int code;
730             ObtainWriteLockNoBlock(&client->lock, code);
731             if (code < 0) {
732                 char hoststr[16];
733                 ViceLog(0,
734                         ("Warning: h_TossStuff_r failed: Host %s:%d client %x was locked.\n",
735                          afs_inet_ntoa_r(host->host, hoststr),
736                          ntohs(host->port), client));
737                 return;
738             }
739                  
740             if (client->refCount) {
741                 char hoststr[16];
742                 ViceLog(0,
743                         ("Warning: h_TossStuff_r failed: Host %s:%d client %x refcount %d.\n",
744                          afs_inet_ntoa_r(host->host, hoststr),
745                          ntohs(host->port), client, client->refCount));
746                 /* This is the same thing we do if the host is locked */
747                 ReleaseWriteLock(&client->lock);
748                 return;
749             }
750             client->CPS.prlist_len = 0;
751             if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
752                 free(client->CPS.prlist_val);
753             client->CPS.prlist_val = NULL;
754             CurrentConnections--;
755             *cp = client->next;
756             ReleaseWriteLock(&client->lock);
757             FreeCE(client);
758         } else
759             cp = &client->next;
760     }
761
762     /* We've just cleaned out all the deleted clients; clear the flag */
763     host->hostFlags &= ~CLIENTDELETED;
764
765     if (host->hostFlags & HOSTDELETED) {
766         register struct h_hashChain **hp, *th;
767         register struct rx_connection *rxconn;
768         afsUUID *uuidp;
769         struct AddrPort hostAddrPort;
770         int i;
771
772         if (host->Console & 1)
773             Console--;
774         if ((rxconn = host->callback_rxcon)) {
775             host->callback_rxcon = (struct rx_connection *)0;
776             rx_DestroyConnection(rxconn);
777         }
778         if (host->hcps.prlist_val)
779             free(host->hcps.prlist_val);
780         host->hcps.prlist_val = NULL;
781         host->hcps.prlist_len = 0;
782         DeleteAllCallBacks_r(host, 1);
783         host->hostFlags &= ~RESETDONE;  /* just to be safe */
784
785         /* if alternate addresses do not exist */
786         if (!(host->interface)) {
787             for (hp = &hostHashTable[h_HashIndex(host->host)]; (th = *hp);
788                  hp = &th->next) {
789                 assert(th->hostPtr);
790                 if (th->hostPtr == host) {
791                     *hp = th->next;
792                     h_DeleteList_r(host);
793                     FreeHT(host);
794                     free(th);
795                     break;
796                 }
797             }
798         } else {
799             /* delete all hash entries for the UUID */
800             uuidp = &host->interface->uuid;
801             for (hp = &hostUuidHashTable[h_UuidHashIndex(uuidp)]; (th = *hp);
802                  hp = &th->next) {
803                 assert(th->hostPtr);
804                 if (th->hostPtr == host) {
805                     *hp = th->next;
806                     free(th);
807                     break;
808                 }
809             }
810             /* delete all hash entries for alternate addresses */
811             assert(host->interface->numberOfInterfaces > 0);
812             for (i = 0; i < host->interface->numberOfInterfaces; i++) {
813                 hostAddrPort = host->interface->interface[i];
814
815                 for (hp = &hostHashTable[h_HashIndex(hostAddrPort.addr)]; (th = *hp);
816                      hp = &th->next) {
817                     assert(th->hostPtr);
818                     if (th->hostPtr == host) {
819                         *hp = th->next;
820                         free(th);
821                         break;
822                     }
823                 }
824             }
825             free(host->interface);
826             host->interface = NULL;
827             h_DeleteList_r(host);       /* remove host from global host List */
828             FreeHT(host);
829         }                       /* if alternate address exists */
830     }
831 }                               /*h_TossStuff_r */
832
833
834 /* h_Enumerate: Calls (*proc)(host, held, param) for at least each host in the
835  * system at the start of the enumeration (perhaps more).  Hosts may be deleted
836  * (have delete flag set); ditto for clients.  (*proc) is always called with
837  * host h_held().  The hold state of the host with respect to this lwp is passed
838  * to (*proc) as the param held.  The proc should return 0 if the host should be
839  * released, 1 if it should be held after enumeration.
840  */
841 void
842 h_Enumerate(int (*proc) (), char *param)
843 {
844     register struct host *host, **list;
845     register int *held;
846     register int i, count;
847
848     H_LOCK;
849     if (hostCount == 0) {
850         H_UNLOCK;
851         return;
852     }
853     list = (struct host **)malloc(hostCount * sizeof(struct host *));
854     if (!list) {
855         ViceLog(0, ("Failed malloc in h_Enumerate\n"));
856         assert(0);
857     }
858     held = (int *)malloc(hostCount * sizeof(int));
859     if (!held) {
860         ViceLog(0, ("Failed malloc in h_Enumerate\n"));
861         assert(0);
862     }
863     for (count = 0, host = hostList; host; host = host->next, count++) {
864         list[count] = host;
865         if (!(held[count] = h_Held_r(host)))
866             h_Hold_r(host);
867     }
868     assert(count == hostCount);
869     H_UNLOCK;
870     for (i = 0; i < count; i++) {
871         held[i] = (*proc) (list[i], held[i], param);
872         if (!H_ENUMERATE_ISSET_HELD(held[i]))
873             h_Release(list[i]); /* this might free up the host */
874         /* bail out of the enumeration early */
875         if (H_ENUMERATE_ISSET_BAIL(held[i]))
876             break;
877     }
878     free((void *)list);
879     free((void *)held);
880 }                               /*h_Enumerate */
881
882 /* h_Enumerate_r (revised):
883  * Calls (*proc)(host, held, param) for each host in hostList, starting
884  * at enumstart
885  * Hosts may be deleted (have delete flag set); ditto for clients.
886  * (*proc) is always called with
887  * host h_held() and the global host lock (H_LOCK) locked.The hold state of the
888  * host with respect to this lwp is passed to (*proc) as the param held.
889  * The proc should return 0 if the host should be released, 1 if it should
890  * be held after enumeration.
891  */
892 void
893 h_Enumerate_r(int (*proc) (), struct host *enumstart, char *param)
894 {
895     register struct host *host, *next;
896     register int held, nheld;
897
898     if (hostCount == 0) {
899         return;
900     }
901     if (enumstart && !(held = h_Held_r(enumstart)))
902         h_Hold_r(enumstart); 
903     for (host = enumstart; host; host = next, held = nheld) {
904         next = host->next;
905         if (next && !(nheld = h_Held_r(next)) && !H_ENUMERATE_ISSET_BAIL(held))
906             h_Hold_r(next);
907         held = (*proc) (host, held, param);
908         if (!H_ENUMERATE_ISSET_HELD(held))
909             h_Release_r(host); /* this might free up the host */
910         if (H_ENUMERATE_ISSET_BAIL(held))
911             break;
912     }
913 }                               /*h_Enumerate_r */
914
915 /* inserts a new HashChain structure corresponding to this UUID */
916 static void
917 h_AddHostToUuidHashTable_r(struct afsUUID *uuid, struct host *host)
918 {
919     int index;
920     struct h_hashChain *chain;
921
922     /* hash into proper bucket */
923     index = h_UuidHashIndex(uuid);
924
925     /* insert into beginning of list for this bucket */
926     chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
927     if (!chain) {
928         ViceLog(0, ("Failed malloc in h_AddHostToUuidHashTable_r\n"));
929         assert(0);
930     }
931     assert(chain);
932     chain->hostPtr = host;
933     chain->next = hostUuidHashTable[index];
934     hostUuidHashTable[index] = chain;
935 }
936
937
938 /* inserts a new HashChain structure corresponding to this address */
939 static void
940 h_AddHostToHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host)
941 {
942     int index;
943     struct h_hashChain *chain;
944
945     /* hash into proper bucket */
946     index = h_HashIndex(addr);
947
948     /* don't add the same entry multiple times */
949     for (chain = hostHashTable[index]; chain; chain = chain->next) {
950         if (chain->hostPtr == host && chain->addr == addr && chain->port == port)
951             return;
952     }
953
954     /* insert into beginning of list for this bucket */
955     chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
956     if (!chain) {
957         ViceLog(0, ("Failed malloc in h_AddHostToHashTable_r\n"));
958         assert(0);
959     }
960     chain->hostPtr = host;
961     chain->next = hostHashTable[index];
962     chain->addr = addr;
963     chain->port = port;
964     hostHashTable[index] = chain;
965 }
966
967 /*
968  * This is called with host locked and held. At this point, the
969  * hostHashTable should not be having entries for the alternate
970  * interfaces. This function has to insert these entries in the
971  * hostHashTable.
972  *
973  * All addresses are in network byte order.
974  */
975 int
976 addInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
977 {
978     int i;
979     int number;
980     int found;
981     struct Interface *interface;
982     char hoststr[16], hoststr2[16];
983
984     assert(host);
985     assert(host->interface);
986
987     ViceLog(125, ("addInterfaceAddr : host %s:%d addr %s:%d\n", 
988                    afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), 
989                    afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
990
991     /*
992      * Make sure this address is on the list of known addresses
993      * for this host.
994      */
995     number = host->interface->numberOfInterfaces;
996     for (i = 0, found = 0; i < number && !found; i++) {
997         if (host->interface->interface[i].addr == addr &&
998             host->interface->interface[i].port == port)
999             found = 1;
1000     }
1001     if (!found) {
1002         interface = (struct Interface *)
1003             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * number));
1004         if (!interface) {
1005             ViceLog(0, ("Failed malloc in addInterfaceAddr_r\n"));
1006             assert(0);
1007         }
1008         interface->numberOfInterfaces = number + 1;
1009         interface->uuid = host->interface->uuid;
1010         for (i = 0; i < number; i++)
1011             interface->interface[i] = host->interface->interface[i];
1012         interface->interface[number].addr = addr;
1013         interface->interface[number].port = port;
1014         free(host->interface);
1015         host->interface = interface;
1016     }
1017
1018     /*
1019      * Create a hash table entry for this address
1020      */
1021     h_AddHostToHashTable_r(addr, port, host);
1022
1023     return 0;
1024 }
1025
1026
1027 /*
1028  * This is called with host locked and held. At this point, the
1029  * hostHashTable should not be having entries for the alternate
1030  * interfaces. This function has to insert these entries in the
1031  * hostHashTable.
1032  *
1033  * All addresses are in network byte order.
1034  */
1035 int
1036 removeInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1037 {
1038     int i;
1039     int number;
1040     int found;
1041     struct Interface *interface;
1042     char hoststr[16], hoststr2[16];
1043
1044     assert(host);
1045     assert(host->interface);
1046
1047     ViceLog(125, ("removeInterfaceAddr : host %s:%d addr %s:%d\n", 
1048                    afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), 
1049                    afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
1050
1051     /*
1052      * Make sure this address is on the list of known addresses
1053      * for this host.
1054      */
1055     interface = host->interface;
1056     number = host->interface->numberOfInterfaces;
1057     for (i = 0, found = 0; i < number; i++) {
1058         if (interface->interface[i].addr == addr &&
1059             interface->interface[i].port == port) {
1060             found = 1;
1061             break;
1062         }
1063     }
1064     if (found) {
1065         number--;
1066         for (; i < number; i++) {
1067             interface->interface[i].addr = interface->interface[i+1].addr;
1068             interface->interface[i].port = interface->interface[i+1].port;
1069         }
1070         interface->numberOfInterfaces = number;
1071     }
1072
1073     /*
1074      * Remove the hash table entry for this address
1075      */
1076     h_DeleteHostFromHashTableByAddr_r(addr, port, host);
1077
1078     return 0;
1079 }
1080
1081
1082 /* Host is returned held */
1083 struct host *
1084 h_GetHost_r(struct rx_connection *tcon)
1085 {
1086     struct host *host;
1087     struct host *oldHost;
1088     int code;
1089     int held, oheld;
1090     struct interfaceAddr interf;
1091     int interfValid = 0;
1092     struct Identity *identP = NULL;
1093     afs_uint32 haddr;
1094     afs_uint16 hport;
1095     char hoststr[16], hoststr2[16];
1096     Capabilities caps;
1097     struct rx_connection *cb_conn = NULL;
1098
1099     caps.Capabilities_val = NULL;
1100
1101     haddr = rxr_HostOf(tcon);
1102     hport = rxr_PortOf(tcon);
1103   retry:
1104     if (caps.Capabilities_val)
1105         free(caps.Capabilities_val);
1106     caps.Capabilities_val = NULL;
1107     caps.Capabilities_len = 0;
1108
1109     code = 0;
1110     host = h_Lookup_r(haddr, hport, &held);
1111     identP = (struct Identity *)rx_GetSpecific(tcon, rxcon_ident_key);
1112     if (host && !identP && !(host->Console & 1)) {
1113         /* This is a new connection, and we already have a host
1114          * structure for this address. Verify that the identity
1115          * of the caller matches the identity in the host structure.
1116          */
1117         h_Lock_r(host);
1118         if (!(host->hostFlags & ALTADDR)) {
1119             /* Another thread is doing initialization */
1120             h_Unlock_r(host);
1121             if (!held)
1122                 h_Release_r(host);
1123             ViceLog(125,
1124                     ("Host %s:%d starting h_Lookup again\n",
1125                      afs_inet_ntoa_r(host->host, hoststr),
1126                      ntohs(host->port)));
1127             goto retry;
1128         }
1129         host->hostFlags &= ~ALTADDR;
1130         cb_conn = host->callback_rxcon;
1131         rx_GetConnection(cb_conn);
1132         H_UNLOCK;
1133         code =
1134             RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1135         if (code == RXGEN_OPCODE)
1136             code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1137         rx_PutConnection(cb_conn);
1138         cb_conn=NULL;
1139         H_LOCK;
1140         if (code == RXGEN_OPCODE) {
1141             identP = (struct Identity *)malloc(sizeof(struct Identity));
1142             if (!identP) {
1143                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1144                 assert(0);
1145             }
1146             identP->valid = 0;
1147             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1148             /* The host on this connection was unable to respond to 
1149              * the WhoAreYou. We will treat this as a new connection
1150              * from the existing host. The worst that can happen is
1151              * that we maintain some extra callback state information */
1152             if (host->interface) {
1153                 ViceLog(0,
1154                         ("Host %s:%d used to support WhoAreYou, deleting.\n",
1155                          afs_inet_ntoa_r(host->host, hoststr),
1156                          ntohs(host->port)));
1157                 host->hostFlags |= HOSTDELETED;
1158                 h_Unlock_r(host);
1159                 if (!held)
1160                     h_Release_r(host);
1161                 host = NULL;
1162                 goto retry;
1163             }
1164         } else if (code == 0) {
1165             interfValid = 1;
1166             identP = (struct Identity *)malloc(sizeof(struct Identity));
1167             if (!identP) {
1168                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1169                 assert(0);
1170             }
1171             identP->valid = 1;
1172             identP->uuid = interf.uuid;
1173             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1174             /* Check whether the UUID on this connection matches
1175              * the UUID in the host structure. If they don't match
1176              * then this is not the same host as before. */
1177             if (!host->interface
1178                 || !afs_uuid_equal(&interf.uuid, &host->interface->uuid)) {
1179                 ViceLog(25,
1180                         ("Host %s:%d has changed its identity, deleting.\n",
1181                          afs_inet_ntoa_r(host->host, hoststr), host->port));
1182                 host->hostFlags |= HOSTDELETED;
1183                 h_Unlock_r(host);
1184                 if (!held)
1185                     h_Release_r(host);
1186                 host = NULL;
1187                 goto retry;
1188             }
1189         } else {
1190             afs_inet_ntoa_r(host->host, hoststr);
1191             ViceLog(0,
1192                     ("CB: WhoAreYou failed for %s:%d, error %d\n", hoststr,
1193                      ntohs(host->port), code));
1194             host->hostFlags |= VENUSDOWN;
1195         }
1196         if (caps.Capabilities_val
1197             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
1198             host->hostFlags |= HERRORTRANS;
1199         else
1200             host->hostFlags &= ~(HERRORTRANS);
1201         host->hostFlags |= ALTADDR;
1202         h_Unlock_r(host);
1203     } else if (host) {
1204         if (!(host->hostFlags & ALTADDR)) {
1205             /* another thread is doing the initialisation */
1206             ViceLog(125,
1207                     ("Host %s:%d waiting for host-init to complete\n",
1208                      afs_inet_ntoa_r(host->host, hoststr),
1209                      ntohs(host->port)));
1210             h_Lock_r(host);
1211             h_Unlock_r(host);
1212             if (!held)
1213                 h_Release_r(host);
1214             ViceLog(125,
1215                     ("Host %s:%d starting h_Lookup again\n",
1216                      afs_inet_ntoa_r(host->host, hoststr),
1217                      ntohs(host->port)));
1218             goto retry;
1219         }
1220         /* We need to check whether the identity in the host structure
1221          * matches the identity on the connection. If they don't match
1222          * then treat this a new host. */
1223         if (!(host->Console & 1)
1224             && ((!identP->valid && host->interface)
1225                 || (identP->valid && !host->interface)
1226                 || (identP->valid
1227                     && !afs_uuid_equal(&identP->uuid,
1228                                        &host->interface->uuid)))) {
1229             char uuid1[128], uuid2[128];
1230             if (identP->valid)
1231                 afsUUID_to_string(&identP->uuid, uuid1, 127);
1232             if (host->interface)
1233                 afsUUID_to_string(&host->interface->uuid, uuid2, 127);
1234             ViceLog(0,
1235                     ("CB: new identity for host %s:%d, deleting(%x %x %s %s)\n",
1236                      afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
1237                      identP->valid, host->interface,
1238                      identP->valid ? uuid1 : "",
1239                      host->interface ? uuid2 : ""));
1240
1241             /* The host in the cache is not the host for this connection */
1242             host->hostFlags |= HOSTDELETED;
1243             h_Unlock_r(host);
1244             if (!held)
1245                 h_Release_r(host);
1246             goto retry;
1247         }
1248     } else {
1249         host = h_Alloc_r(tcon); /* returned held and locked */
1250         h_gethostcps_r(host, FT_ApproxTime());
1251         if (!(host->Console & 1)) {
1252             int pident = 0;
1253             cb_conn = host->callback_rxcon;
1254             rx_GetConnection(cb_conn);
1255             H_UNLOCK;
1256             code =
1257                 RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1258             if (code == RXGEN_OPCODE)
1259                 code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1260             rx_PutConnection(cb_conn);
1261             cb_conn=NULL;
1262             H_LOCK;
1263             if (code == RXGEN_OPCODE) {
1264                 if (!identP)
1265                     identP =
1266                         (struct Identity *)malloc(sizeof(struct Identity));
1267                 else
1268                     pident = 1;
1269
1270                 if (!identP) {
1271                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1272                     assert(0);
1273                 }
1274                 identP->valid = 0;
1275                 if (!pident)
1276                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1277                 ViceLog(25,
1278                         ("Host %s:%d does not support WhoAreYou.\n",
1279                          afs_inet_ntoa_r(host->host, hoststr),
1280                          ntohs(host->port)));
1281                 code = 0;
1282             } else if (code == 0) {
1283                 if (!identP)
1284                     identP =
1285                         (struct Identity *)malloc(sizeof(struct Identity));
1286                 else
1287                     pident = 1;
1288
1289                 if (!identP) {
1290                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1291                     assert(0);
1292                 }
1293                 identP->valid = 1;
1294                 interfValid = 1;
1295                 identP->uuid = interf.uuid;
1296                 if (!pident)
1297                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1298                 ViceLog(25,
1299                         ("WhoAreYou success on %s:%d\n",
1300                          afs_inet_ntoa_r(host->host, hoststr),
1301                          ntohs(host->port)));
1302             }
1303             if (code == 0 && !identP->valid) {
1304                 cb_conn = host->callback_rxcon;
1305                 rx_GetConnection(cb_conn);
1306                 H_UNLOCK;
1307                 code = RXAFSCB_InitCallBackState(cb_conn);
1308                 rx_PutConnection(cb_conn);
1309                 cb_conn=NULL;
1310                 H_LOCK;
1311             } else if (code == 0) {
1312                 oldHost = h_LookupUuid_r(&identP->uuid);
1313                 if (oldHost) {
1314                     int probefail = 0;
1315
1316                     if (!(oheld = h_Held_r(oldHost)))
1317                         h_Hold_r(oldHost);
1318                     h_Lock_r(oldHost);
1319
1320                     if (oldHost->interface) {
1321                         int code2;
1322                         afsUUID uuid = oldHost->interface->uuid;
1323                         cb_conn = oldHost->callback_rxcon;
1324                         rx_GetConnection(cb_conn);
1325                         rx_SetConnDeadTime(cb_conn, 2);
1326                         rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1327                         H_UNLOCK;
1328                         code2 = RXAFSCB_ProbeUuid(cb_conn, &uuid);
1329                         H_LOCK;
1330                         rx_SetConnDeadTime(cb_conn, 50);
1331                         rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1332                         rx_PutConnection(cb_conn);
1333                         cb_conn=NULL;
1334                         if (code2) {
1335                             /* The primary address is either not responding or
1336                              * is not the client we are looking for.  
1337                              * MultiProbeAlternateAddress_r() will remove the
1338                              * alternate interfaces that do not have the same
1339                              * Uuid. */
1340                             ViceLog(0,("CB: ProbeUuid for %s:%d failed %d\n",
1341                                          afs_inet_ntoa_r(oldHost->host, hoststr),
1342                                          ntohs(oldHost->port),code2));
1343                             MultiProbeAlternateAddress_r(oldHost);
1344                             probefail = 1;
1345                         }
1346                     } else {
1347                         probefail = 1;
1348                     }
1349
1350                     /* This is a new address for an existing host. Update
1351                      * the list of interfaces for the existing host and
1352                      * delete the host structure we just allocated. */
1353                     if (oldHost->host != haddr || oldHost->port != hport) {
1354                         struct rx_connection *rxconn;
1355
1356                         ViceLog(25,
1357                                 ("CB: new addr %s:%d for old host %s:%d\n",
1358                                   afs_inet_ntoa_r(haddr, hoststr),
1359                                   ntohs(hport), 
1360                                   afs_inet_ntoa_r(oldHost->host, hoststr2),
1361                                   ntohs(oldHost->port)));
1362                         if (probefail || oldHost->host == haddr) {
1363                             /* The probe failed which means that the old address is 
1364                              * either unreachable or is not the same host we were just
1365                              * contacted by.  We will also remove addresses if only
1366                              * the port has changed because that indicates the client
1367                              * is behind a NAT. 
1368                              */
1369                             removeInterfaceAddr_r(oldHost, oldHost->host, oldHost->port);
1370                         } else {
1371                             int i, found;
1372                             struct Interface *interface = oldHost->interface;
1373                             int number = oldHost->interface->numberOfInterfaces;
1374                             for (i = 0, found = 0; i < number; i++) {
1375                                 if (interface->interface[i].addr == haddr &&
1376                                     interface->interface[i].port != hport) {
1377                                     found = 1;
1378                                     break;
1379                                 }
1380                             }
1381                             if (found) {
1382                                 /* We have just been contacted by a client that has been
1383                                  * seen from behind a NAT and at least one other address.
1384                                  */
1385                                 removeInterfaceAddr_r(oldHost, haddr, interface->interface[i].port);
1386                             }
1387                         }
1388                         addInterfaceAddr_r(oldHost, haddr, hport);
1389                         oldHost->host = haddr;
1390                         oldHost->port = hport;
1391                         rxconn = oldHost->callback_rxcon;
1392                         oldHost->callback_rxcon = host->callback_rxcon;
1393                         host->callback_rxcon = NULL;
1394                         
1395                         if (rxconn) {
1396                             struct client *client;
1397                             /*
1398                              * If rx_DestroyConnection calls h_FreeConnection we will
1399                              * deadlock on the host_glock_mutex. Work around the problem
1400                              * by unhooking the client from the connection before
1401                              * destroying the connection.
1402                              */
1403                             client = rx_GetSpecific(rxconn, rxcon_client_key);
1404                             rx_SetSpecific(rxconn, rxcon_client_key, (void *)0);
1405                             rx_DestroyConnection(rxconn);
1406                         }
1407                     }
1408                     host->hostFlags |= HOSTDELETED;
1409                     h_Unlock_r(host);
1410                     /* release host because it was allocated by h_Alloc_r */
1411                     h_Release_r(host);
1412                     host = oldHost;
1413                     /* the new host is held and locked */
1414                 } else {
1415                     /* This really is a new host */
1416                     h_AddHostToUuidHashTable_r(&identP->uuid, host);
1417                     cb_conn = host->callback_rxcon;
1418                     rx_GetConnection(cb_conn);          
1419                     H_UNLOCK;
1420                     code =
1421                         RXAFSCB_InitCallBackState3(cb_conn,
1422                                                    &FS_HostUUID);
1423                     rx_PutConnection(cb_conn);
1424                     cb_conn=NULL;
1425                     H_LOCK;
1426                     if (code == 0) {
1427                         ViceLog(25,
1428                                 ("InitCallBackState3 success on %s:%d\n",
1429                                  afs_inet_ntoa_r(host->host, hoststr),
1430                                  ntohs(host->port)));
1431                         assert(interfValid == 1);
1432                         initInterfaceAddr_r(host, &interf);
1433                     }
1434                 }
1435             }
1436             if (code) {
1437                 afs_inet_ntoa_r(host->host, hoststr);
1438                 ViceLog(0,
1439                         ("CB: RCallBackConnectBack failed for %s:%d\n",
1440                          hoststr, ntohs(host->port)));
1441                 host->hostFlags |= VENUSDOWN;
1442             } else {
1443                 ViceLog(125,
1444                         ("CB: RCallBackConnectBack succeeded for %s:%d\n",
1445                          hoststr, ntohs(host->port)));
1446                 host->hostFlags |= RESETDONE;
1447             }
1448         }
1449         if (caps.Capabilities_val
1450             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
1451             host->hostFlags |= HERRORTRANS;
1452         else
1453             host->hostFlags &= ~(HERRORTRANS);
1454         host->hostFlags |= ALTADDR;     /* host structure initialization complete */
1455         h_Unlock_r(host);
1456     }
1457     if (caps.Capabilities_val)
1458         free(caps.Capabilities_val);
1459     caps.Capabilities_val = NULL;
1460     caps.Capabilities_len = 0;
1461     return host;
1462
1463 }                               /*h_GetHost_r */
1464
1465
1466 static char localcellname[PR_MAXNAMELEN + 1];
1467 char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
1468 int  num_lrealms = -1;
1469
1470 /* not reentrant */
1471 void
1472 h_InitHostPackage()
1473 {
1474     afsconf_GetLocalCell(confDir, localcellname, PR_MAXNAMELEN);
1475     if (num_lrealms == -1) {
1476         int i;
1477         for (i=0; i<AFS_NUM_LREALMS; i++) {
1478             if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
1479                 break;
1480         }
1481
1482         if (i=0) {
1483             ViceLog(0,
1484                     ("afs_krb_get_lrealm failed, using %s.\n",
1485                      localcellname));
1486             strncpy(local_realms[0], localcellname, AFS_REALM_SZ);
1487             num_lrealms = i =1;
1488         } else {
1489             num_lrealms = i;
1490         }
1491
1492         /* initialize the rest of the local realms to nullstring for debugging */
1493         for (; i<AFS_NUM_LREALMS; i++)
1494             local_realms[i][0] = '\0';
1495     }
1496     rxcon_ident_key = rx_KeyCreate((rx_destructor_t) free);
1497     rxcon_client_key = rx_KeyCreate((rx_destructor_t) 0);
1498 #ifdef AFS_PTHREAD_ENV
1499     assert(pthread_mutex_init(&host_glock_mutex, NULL) == 0);
1500 #endif /* AFS_PTHREAD_ENV */
1501 }
1502
1503 static int
1504 MapName_r(char *aname, char *acell, afs_int32 * aval)
1505 {
1506     namelist lnames;
1507     idlist lids;
1508     afs_int32 code;
1509     afs_int32 anamelen, cnamelen;
1510     int foreign = 0;
1511     char *tname;
1512
1513     anamelen = strlen(aname);
1514     if (anamelen >= PR_MAXNAMELEN)
1515         return -1;              /* bad name -- caller interprets this as anonymous, but retries later */
1516
1517     lnames.namelist_len = 1;
1518     lnames.namelist_val = (prname *) aname;     /* don't malloc in the common case */
1519     lids.idlist_len = 0;
1520     lids.idlist_val = NULL;
1521
1522     cnamelen = strlen(acell);
1523     if (cnamelen) {
1524         if (afs_is_foreign_ticket_name(aname, NULL, acell, localcellname)) {
1525             ViceLog(2,
1526                     ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealms={%s,%s,%s,%s}\n",
1527                     acell, localcellname, local_realms[0],local_realms[1],local_realms[2],local_realms[3]));
1528             if ((anamelen + cnamelen + 1) >= PR_MAXNAMELEN) {
1529                 ViceLog(2,
1530                         ("MapName: Name too long, using AnonymousID for %s@%s\n",
1531                          aname, acell));
1532                 *aval = AnonymousID;
1533                 return 0;
1534             }
1535             foreign = 1;        /* attempt cross-cell authentication */
1536             tname = (char *)malloc(PR_MAXNAMELEN);
1537             if (!tname) {
1538                 ViceLog(0, ("Failed malloc in MapName_r\n"));
1539                 assert(0);
1540             }
1541             strcpy(tname, aname);
1542             tname[anamelen] = '@';
1543             strcpy(tname + anamelen + 1, acell);
1544             lnames.namelist_val = (prname *) tname;
1545         }
1546     }
1547
1548     H_UNLOCK;
1549     code = pr_NameToId(&lnames, &lids);
1550     H_LOCK;
1551     if (code == 0) {
1552         if (lids.idlist_val) {
1553             *aval = lids.idlist_val[0];
1554             if (*aval == AnonymousID) {
1555                 ViceLog(2,
1556                         ("MapName: NameToId on %s returns anonymousID\n",
1557                          lnames.namelist_val));
1558             }
1559             free(lids.idlist_val);      /* return parms are not malloced in stub if server proc aborts */
1560         } else {
1561             ViceLog(0,
1562                     ("MapName: NameToId on '%s' is unknown\n",
1563                      lnames.namelist_val));
1564             code = -1;
1565         }
1566     }
1567
1568     if (foreign) {
1569         free(lnames.namelist_val);      /* We allocated this above, so we must free it now. */
1570     }
1571     return code;
1572 }
1573
1574 /*MapName*/
1575
1576
1577 /* NOTE: this returns the client with a Write lock and a refCount */
1578 struct client *
1579 h_ID2Client(afs_int32 vid)
1580 {
1581     register struct client *client;
1582     register struct host *host;
1583
1584     H_LOCK;
1585     for (host = hostList; host; host = host->next) {
1586         if (host->hostFlags & HOSTDELETED)
1587             continue;
1588         for (client = host->FirstClient; client; client = client->next) {
1589             if (!client->deleted && client->ViceId == vid) {
1590                 client->refCount++;
1591                 H_UNLOCK;
1592                 ObtainWriteLock(&client->lock);
1593                 return client;
1594             }
1595         }
1596     }
1597
1598     H_UNLOCK;
1599     return NULL;
1600 }
1601
1602 /*
1603  * Called by the server main loop.  Returns a h_Held client, which must be
1604  * released later the main loop.  Allocates a client if the matching one
1605  * isn't around. The client is returned with its reference count incremented
1606  * by one. The caller must call h_ReleaseClient_r when finished with
1607  * the client.
1608  *
1609  * the client->host is returned held.  h_ReleaseClient_r does not release
1610  * the hold on client->host.
1611  */
1612 struct client *
1613 h_FindClient_r(struct rx_connection *tcon)
1614 {
1615     register struct client *client;
1616     register struct host *host;
1617     struct client *oldClient;
1618     afs_int32 viceid;
1619     afs_int32 expTime;
1620     afs_int32 code;
1621     int authClass;
1622 #if (64-MAXKTCNAMELEN)
1623     ticket name length != 64
1624 #endif
1625     char tname[64];
1626     char tinst[64];
1627     char uname[PR_MAXNAMELEN];
1628     char tcell[MAXKTCREALMLEN];
1629     int fail = 0;
1630     int created = 0;
1631
1632     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1633     if (client && client->sid == rxr_CidOf(tcon) 
1634         && client->VenusEpoch == rxr_GetEpoch(tcon)) {
1635         client->refCount++;
1636         h_Hold_r(client->host);
1637         if (!client->deleted && client->prfail != 2) {  
1638             /* Could add shared lock on client here */
1639             /* note that we don't have to lock entry in this path to
1640              * ensure CPS is initialized, since we don't call rx_SetSpecific
1641              * until initialization is done, and we only get here if
1642              * rx_GetSpecific located the client structure.
1643              */
1644             return client;
1645         }
1646         H_UNLOCK;
1647         ObtainWriteLock(&client->lock); /* released at end */
1648         H_LOCK;
1649     }
1650
1651     authClass = rx_SecurityClassOf((struct rx_connection *)tcon);
1652     ViceLog(5,
1653             ("FindClient: authenticating connection: authClass=%d\n",
1654              authClass));
1655     if (authClass == 1) {
1656         /* A bcrypt tickets, no longer supported */
1657         ViceLog(1, ("FindClient: bcrypt ticket, using AnonymousID\n"));
1658         viceid = AnonymousID;
1659         expTime = 0x7fffffff;
1660     } else if (authClass == 2) {
1661         afs_int32 kvno;
1662
1663         /* kerberos ticket */
1664         code = rxkad_GetServerInfo(tcon, /*level */ 0, &expTime,
1665                                    tname, tinst, tcell, &kvno);
1666         if (code) {
1667             ViceLog(1, ("Failed to get rxkad ticket info\n"));
1668             viceid = AnonymousID;
1669             expTime = 0x7fffffff;
1670         } else {
1671             int ilen = strlen(tinst);
1672             ViceLog(5,
1673                     ("FindClient: rxkad conn: name=%s,inst=%s,cell=%s,exp=%d,kvno=%d\n",
1674                      tname, tinst, tcell, expTime, kvno));
1675             strncpy(uname, tname, sizeof(uname));
1676             if (ilen) {
1677                 if (strlen(uname) + 1 + ilen >= sizeof(uname))
1678                     goto bad_name;
1679                 strcat(uname, ".");
1680                 strcat(uname, tinst);
1681             }
1682             /* translate the name to a vice id */
1683             code = MapName_r(uname, tcell, &viceid);
1684             if (code) {
1685               bad_name:
1686                 ViceLog(1,
1687                         ("failed to map name=%s, cell=%s -> code=%d\n", uname,
1688                          tcell, code));
1689                 fail = 1;
1690                 viceid = AnonymousID;
1691                 expTime = 0x7fffffff;
1692             }
1693         }
1694     } else {
1695         viceid = AnonymousID;   /* unknown security class */
1696         expTime = 0x7fffffff;
1697     }
1698
1699     if (!client) { /* loop */
1700         host = h_GetHost_r(tcon);       /* Returns it h_Held */
1701
1702     retryfirstclient:
1703         /* First try to find the client structure */
1704         for (client = host->FirstClient; client; client = client->next) {
1705             if (!client->deleted && (client->sid == rxr_CidOf(tcon))
1706                 && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
1707                 client->refCount++;
1708                 H_UNLOCK;
1709                 ObtainWriteLock(&client->lock);
1710                 H_LOCK;
1711                 break;
1712             }
1713         }
1714
1715         /* Still no client structure - get one */
1716         if (!client) {
1717             h_Lock_r(host);
1718             /* Retry to find the client structure */
1719             for (client = host->FirstClient; client; client = client->next) {
1720                 if (!client->deleted && (client->sid == rxr_CidOf(tcon))
1721                     && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
1722                     h_Unlock_r(host);
1723                     goto retryfirstclient;
1724                 }
1725             }
1726             created = 1;
1727             client = GetCE();
1728             ObtainWriteLock(&client->lock);
1729             client->refCount = 1;
1730             client->host = host;
1731 #if FS_STATS_DETAILED
1732             client->InSameNetwork = host->InSameNetwork;
1733 #endif /* FS_STATS_DETAILED */
1734             client->ViceId = viceid;
1735             client->expTime = expTime;  /* rx only */
1736             client->authClass = authClass;      /* rx only */
1737             client->sid = rxr_CidOf(tcon);
1738             client->VenusEpoch = rxr_GetEpoch(tcon);
1739             client->CPS.prlist_val = NULL;
1740             client->CPS.prlist_len = 0;
1741             h_Unlock_r(host);
1742         }
1743     }
1744     client->prfail = fail;
1745
1746     if (!(client->CPS.prlist_val) || (viceid != client->ViceId)) {
1747         client->CPS.prlist_len = 0;
1748         if (client->CPS.prlist_val && (client->ViceId != ANONYMOUSID))
1749             free(client->CPS.prlist_val);
1750         client->CPS.prlist_val = NULL;
1751         client->ViceId = viceid;
1752         client->expTime = expTime;
1753
1754         if (viceid == ANONYMOUSID) {
1755             client->CPS.prlist_len = AnonCPS.prlist_len;
1756             client->CPS.prlist_val = AnonCPS.prlist_val;
1757         } else {
1758             H_UNLOCK;
1759             code = pr_GetCPS(viceid, &client->CPS);
1760             H_LOCK;
1761             if (code) {
1762                 char hoststr[16];
1763                 ViceLog(0,
1764                         ("pr_GetCPS failed(%d) for user %d, host %s:%d\n",
1765                          code, viceid, afs_inet_ntoa_r(client->host->host,
1766                                                        hoststr),
1767                          ntohs(client->host->port)));
1768
1769                 /* Although ubik_Call (called by pr_GetCPS) traverses thru
1770                  * all protection servers and reevaluates things if no
1771                  * sync server or quorum is found we could still end up
1772                  * with one of these errors. In such case we would like to
1773                  * reevaluate the rpc call to find if there's cps for this
1774                  * guy. We treat other errors (except network failures
1775                  * ones - i.e. code < 0) as an indication that there is no
1776                  * CPS for this host.  Ideally we could like to deal this
1777                  * problem the other way around (i.e.  if code == NOCPS
1778                  * ignore else retry next time) but the problem is that
1779                  * there're other errors (i.e.  EPERM) for which we don't
1780                  * want to retry and we don't know the whole code list!
1781                  */
1782                 if (code < 0 || code == UNOQUORUM || code == UNOTSYNC)
1783                     client->prfail = 1;
1784             }
1785         }
1786         /* the disabling of system:administrators is so iffy and has so many
1787          * possible failure modes that we will disable it again */
1788         /* Turn off System:Administrator for safety  
1789          * if (AL_IsAMember(SystemId, client->CPS) == 0)
1790          * assert(AL_DisableGroup(SystemId, client->CPS) == 0); */
1791     }
1792
1793     /* Now, tcon may already be set to a rock, since we blocked with no host
1794      * or client locks set above in pr_GetCPS (XXXX some locking is probably
1795      * required).  So, before setting the RPC's rock, we should disconnect
1796      * the RPC from the other client structure's rock.
1797      */
1798     oldClient = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1799     if (oldClient && oldClient != client && oldClient->sid == rxr_CidOf(tcon)
1800         && oldClient->VenusEpoch == rxr_GetEpoch(tcon)) {
1801         char hoststr[16];
1802         if (!oldClient->deleted) {
1803             /* if we didn't create it, it's not ours to put back */
1804             if (created) {
1805                 ViceLog(0, ("FindClient: stillborn client %x(%x); conn %x (host %s:%d) had client %x(%x)\n", 
1806                             client, client->sid, tcon, 
1807                             rxr_AddrStringOf(tcon),
1808                             ntohs(rxr_PortOf(tcon)),
1809                             oldClient, oldClient->sid));
1810                 if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
1811                     free(client->CPS.prlist_val);
1812                 client->CPS.prlist_val = NULL;
1813                 client->CPS.prlist_len = 0;
1814             }
1815             /* We should perhaps check for 0 here */
1816             client->refCount--;
1817             ReleaseWriteLock(&client->lock);
1818             if (created) {
1819                 FreeCE(client);
1820                 created = 0;
1821             } 
1822             oldClient->refCount++;
1823             H_UNLOCK;
1824             ObtainWriteLock(&oldClient->lock);
1825             H_LOCK;
1826             client = oldClient;
1827         } else {
1828             ViceLog(0, ("FindClient: deleted client %x(%x) already had conn %x (host %s:%d), stolen by client %x(%x)\n", 
1829                         oldClient, oldClient->sid, tcon, 
1830                         rxr_AddrStringOf(tcon),
1831                         ntohs(rxr_PortOf(tcon)),
1832                         client, client->sid));
1833             /* rx_SetSpecific will be done immediately below */
1834         }
1835     }
1836     /* Avoid chaining in more than once. */
1837     if (created) {
1838         h_Lock_r(host);
1839         client->next = host->FirstClient;
1840         host->FirstClient = client;
1841         h_Unlock_r(host);
1842         CurrentConnections++;   /* increment number of connections */
1843     }
1844     rx_SetSpecific(tcon, rxcon_client_key, client);
1845     ReleaseWriteLock(&client->lock);
1846
1847     return client;
1848
1849 }                               /*h_FindClient_r */
1850
1851 int
1852 h_ReleaseClient_r(struct client *client)
1853 {
1854     assert(client->refCount > 0);
1855     client->refCount--;
1856     return 0;
1857 }
1858
1859
1860 /*
1861  * Sigh:  this one is used to get the client AGAIN within the individual
1862  * server routines.  This does not bother h_Holding the host, since
1863  * this is assumed already have been done by the server main loop.
1864  * It does check tokens, since only the server routines can return the
1865  * VICETOKENDEAD error code
1866  */
1867 int
1868 GetClient(struct rx_connection *tcon, struct client **cp)
1869 {
1870     register struct client *client;
1871
1872     H_LOCK;
1873     *cp = NULL;
1874     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1875     if (client == NULL) {
1876         ViceLog(0,
1877                 ("GetClient: no client in conn %x (host %s:%d), VBUSYING\n",
1878                  tcon, rxr_AddrStringOf(tcon),ntohs(rxr_PortOf(tcon))));
1879         H_UNLOCK;
1880         return VBUSY;
1881     }
1882     if (rxr_CidOf(tcon) != client->sid || rxr_GetEpoch(tcon) != client->VenusEpoch) {
1883         ViceLog(0,
1884                 ("GetClient: tcon %x tcon sid %d client sid %d\n",
1885                  tcon, rxr_CidOf(tcon), client->sid));
1886         H_UNLOCK;
1887         return VBUSY;
1888     }
1889     if (client && client->LastCall > client->expTime && client->expTime) {
1890         char hoststr[16];
1891         ViceLog(1,
1892                 ("Token for %s at %s:%d expired %d\n", h_UserName(client),
1893                  afs_inet_ntoa_r(client->host->host, hoststr),
1894                  ntohs(client->host->port), client->expTime));
1895         H_UNLOCK;
1896         return VICETOKENDEAD;
1897     }
1898
1899     client->refCount++;
1900     *cp = client;
1901     H_UNLOCK;
1902     return 0;
1903 }                               /*GetClient */
1904
1905 int
1906 PutClient(struct client **cp)
1907 {
1908     if (*cp == NULL) 
1909         return -1;
1910
1911     H_LOCK;
1912     h_ReleaseClient_r(*cp);
1913     *cp = NULL;
1914     H_UNLOCK;
1915     return 0;
1916 }                               /*PutClient */
1917
1918
1919 /* Client user name for short term use.  Note that this is NOT inexpensive */
1920 char *
1921 h_UserName(struct client *client)
1922 {
1923     static char User[PR_MAXNAMELEN + 1];
1924     namelist lnames;
1925     idlist lids;
1926
1927     lids.idlist_len = 1;
1928     lids.idlist_val = (afs_int32 *) malloc(1 * sizeof(afs_int32));
1929     if (!lids.idlist_val) {
1930         ViceLog(0, ("Failed malloc in h_UserName\n"));
1931         assert(0);
1932     }
1933     lnames.namelist_len = 0;
1934     lnames.namelist_val = (prname *) 0;
1935     lids.idlist_val[0] = client->ViceId;
1936     if (pr_IdToName(&lids, &lnames)) {
1937         /* We need to free id we alloced above! */
1938         free(lids.idlist_val);
1939         return "*UNKNOWN USER NAME*";
1940     }
1941     strncpy(User, lnames.namelist_val[0], PR_MAXNAMELEN);
1942     free(lids.idlist_val);
1943     free(lnames.namelist_val);
1944     return User;
1945
1946 }                               /*h_UserName */
1947
1948
1949 void
1950 h_PrintStats()
1951 {
1952     ViceLog(0,
1953             ("Total Client entries = %d, blocks = %d; Host entries = %d, blocks = %d\n",
1954              CEs, CEBlocks, HTs, HTBlocks));
1955
1956 }                               /*h_PrintStats */
1957
1958
1959 static int
1960 h_PrintClient(register struct host *host, int held, StreamHandle_t * file)
1961 {
1962     register struct client *client;
1963     int i;
1964     char tmpStr[256];
1965     char tbuffer[32];
1966     char hoststr[16];
1967     time_t LastCall, expTime;
1968
1969     H_LOCK;
1970     LastCall = host->LastCall;
1971     if (host->hostFlags & HOSTDELETED) {
1972         H_UNLOCK;
1973         return held;
1974     }
1975     (void)afs_snprintf(tmpStr, sizeof tmpStr,
1976                        "Host %s:%d down = %d, LastCall %s",
1977                        afs_inet_ntoa_r(host->host, hoststr),
1978                        ntohs(host->port), (host->hostFlags & VENUSDOWN),
1979                        afs_ctime(&LastCall, tbuffer,
1980                                  sizeof(tbuffer)));
1981     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1982     for (client = host->FirstClient; client; client = client->next) {
1983         if (!client->deleted) {
1984                 expTime = client->expTime;
1985                 (void)afs_snprintf(tmpStr, sizeof tmpStr,
1986                                    "    user id=%d,  name=%s, sl=%s till %s",
1987                                    client->ViceId, h_UserName(client),
1988                                    client->
1989                                    authClass ? "Authenticated" :
1990                                    "Not authenticated",
1991                                    client->
1992                                    authClass ? afs_ctime(&expTime, tbuffer,
1993                                                          sizeof(tbuffer))
1994                                    : "No Limit\n");
1995                 (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1996             (void)afs_snprintf(tmpStr, sizeof tmpStr, "      CPS-%d is [",
1997                                client->CPS.prlist_len);
1998             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1999             if (client->CPS.prlist_val) {
2000                 for (i = 0; i > client->CPS.prlist_len; i++) {
2001                     (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
2002                                        client->CPS.prlist_val[i]);
2003                     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2004                 }
2005             }
2006             sprintf(tmpStr, "]\n");
2007             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2008         }
2009     }
2010     H_UNLOCK;
2011     return held;
2012
2013 }                               /*h_PrintClient */
2014
2015
2016
2017 /*
2018  * Print a list of clients, with last security level and token value seen,
2019  * if known
2020  */
2021 void
2022 h_PrintClients()
2023 {
2024     time_t now;
2025     char tmpStr[256];
2026     char tbuffer[32];
2027
2028     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_CLNTDUMP_FILEPATH, "w");
2029
2030     if (file == NULL) {
2031         ViceLog(0,
2032                 ("Couldn't create client dump file %s\n",
2033                  AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2034         return;
2035     }
2036     now = FT_ApproxTime();
2037     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active users at %s\n",
2038                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
2039     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2040     h_Enumerate(h_PrintClient, (char *)file);
2041     STREAM_REALLYCLOSE(file);
2042     ViceLog(0, ("Created client dump %s\n", AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2043 }
2044
2045
2046
2047
2048 static int
2049 h_DumpHost(register struct host *host, int held, StreamHandle_t * file)
2050 {
2051     int i;
2052     char tmpStr[256];
2053     char hoststr[16];
2054
2055     H_LOCK;
2056     (void)afs_snprintf(tmpStr, sizeof tmpStr,
2057                        "ip:%s port:%d hidx:%d cbid:%d lock:%x last:%u active:%u down:%d del:%d cons:%d cldel:%d\n\t hpfailed:%d hcpsCall:%u hcps [",
2058                        afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), host->index,
2059                        host->cblist, CheckLock(&host->lock), host->LastCall,
2060                        host->ActiveCall, (host->hostFlags & VENUSDOWN),
2061                        host->hostFlags & HOSTDELETED, host->Console,
2062                        host->hostFlags & CLIENTDELETED, host->hcpsfailed,
2063                        host->cpsCall);
2064     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2065     if (host->hcps.prlist_val)
2066         for (i = 0; i < host->hcps.prlist_len; i++) {
2067             (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
2068                                host->hcps.prlist_val[i]);
2069             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2070         }
2071     sprintf(tmpStr, "] [");
2072     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2073     if (host->interface)
2074         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
2075             char hoststr[16];
2076             sprintf(tmpStr, " %s:%d", 
2077                      afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2078                      ntohs(host->interface->interface[i].port));
2079             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2080         }
2081     sprintf(tmpStr, "] holds: ");
2082     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2083
2084     for (i = 0; i < h_maxSlots; i++) {
2085         sprintf(tmpStr, "%04x", host->holds[i]);
2086         (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2087     }
2088     sprintf(tmpStr, " slot/bit: %d/%d\n", h_holdSlot(), h_holdbit());
2089     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2090
2091     H_UNLOCK;
2092     return held;
2093
2094 }                               /*h_DumpHost */
2095
2096
2097 void
2098 h_DumpHosts()
2099 {
2100     time_t now;
2101     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_HOSTDUMP_FILEPATH, "w");
2102     char tmpStr[256];
2103     char tbuffer[32];
2104
2105     if (file == NULL) {
2106         ViceLog(0,
2107                 ("Couldn't create host dump file %s\n",
2108                  AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2109         return;
2110     }
2111     now = FT_ApproxTime();
2112     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active hosts at %s\n",
2113                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
2114     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2115     h_Enumerate(h_DumpHost, (char *)file);
2116     STREAM_REALLYCLOSE(file);
2117     ViceLog(0, ("Created host dump %s\n", AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2118
2119 }                               /*h_DumpHosts */
2120
2121 #ifdef AFS_DEMAND_ATTACH_FS
2122 /*
2123  * demand attach fs
2124  * host state serialization
2125  */
2126 static int h_stateFillHeader(struct host_state_header * hdr);
2127 static int h_stateCheckHeader(struct host_state_header * hdr);
2128 static int h_stateAllocMap(struct fs_dump_state * state);
2129 static int h_stateSaveHost(register struct host * host, int held, struct fs_dump_state * state);
2130 static int h_stateRestoreHost(struct fs_dump_state * state);
2131 static int h_stateRestoreIndex(struct host * h, int held, struct fs_dump_state * state);
2132 static int h_stateVerifyHost(struct host * h, int held, struct fs_dump_state * state);
2133 static int h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port);
2134 static int h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h);
2135 static void h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out);
2136 static void h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out);
2137
2138
2139 /* this procedure saves all host state to disk for fast startup */
2140 int
2141 h_stateSave(struct fs_dump_state * state)
2142 {
2143     AssignInt64(state->eof_offset, &state->hdr->h_offset);
2144
2145     /* XXX debug */
2146     ViceLog(0, ("h_stateSave:  hostCount=%d\n", hostCount));
2147
2148     /* invalidate host state header */
2149     memset(state->h_hdr, 0, sizeof(struct host_state_header));
2150
2151     if (fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2152                             sizeof(struct host_state_header))) {
2153         state->bail = 1;
2154         goto done;
2155     }
2156
2157     fs_stateIncEOF(state, sizeof(struct host_state_header));
2158
2159     h_Enumerate_r(h_stateSaveHost, hostList, (char *)state);
2160     if (state->bail) {
2161         goto done;
2162     }
2163
2164     h_stateFillHeader(state->h_hdr);
2165
2166     /* write the real header to disk */
2167     state->bail = fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2168                                       sizeof(struct host_state_header));
2169
2170  done:
2171     return state->bail;
2172 }
2173
2174 /* demand attach fs
2175  * host state serialization
2176  *
2177  * this procedure restores all host state from a disk for fast startup 
2178  */
2179 int
2180 h_stateRestore(struct fs_dump_state * state)
2181 {
2182     int i, records;
2183
2184     /* seek to the right position and read in the host state header */
2185     if (fs_stateReadHeader(state, &state->hdr->h_offset, state->h_hdr,
2186                            sizeof(struct host_state_header))) {
2187         state->bail = 1;
2188         goto done;
2189     }
2190
2191     /* check the validity of the header */
2192     if (h_stateCheckHeader(state->h_hdr)) {
2193         state->bail = 1;
2194         goto done;
2195     }
2196
2197     records = state->h_hdr->records;
2198
2199     if (h_stateAllocMap(state)) {
2200         state->bail = 1;
2201         goto done;
2202     }
2203
2204     /* iterate over records restoring host state */
2205     for (i=0; i < records; i++) {
2206         if (h_stateRestoreHost(state) != 0) {
2207             state->bail = 1;
2208             break;
2209         }
2210     }
2211
2212  done:
2213     return state->bail;
2214 }
2215
2216 int
2217 h_stateRestoreIndices(struct fs_dump_state * state)
2218 {
2219     h_Enumerate_r(h_stateRestoreIndex, hostList, (char *)state);
2220     return state->bail;
2221 }
2222
2223 static int
2224 h_stateRestoreIndex(struct host * h, int held, struct fs_dump_state * state)
2225 {
2226     if (cb_OldToNew(state, h->cblist, &h->cblist)) {
2227         return H_ENUMERATE_BAIL(held);
2228     }
2229     return held;
2230 }
2231
2232 int
2233 h_stateVerify(struct fs_dump_state * state)
2234 {
2235     h_Enumerate_r(h_stateVerifyHost, hostList, (char *)state);
2236     return state->bail;
2237 }
2238
2239 static int
2240 h_stateVerifyHost(struct host * h, int held, struct fs_dump_state * state)
2241 {
2242     int i;
2243
2244     if (h == NULL) {
2245         ViceLog(0, ("h_stateVerifyHost: error: NULL host pointer in linked list\n"));
2246         return H_ENUMERATE_BAIL(held);
2247     }
2248
2249     if (h->interface) {
2250         for (i = h->interface->numberOfInterfaces-1; i >= 0; i--) {
2251             if (h_stateVerifyAddrHash(state, h, h->interface->interface[i].addr, 
2252                                       h->interface->interface[i].port)) {
2253                 state->bail = 1;
2254             }
2255         }
2256         if (h_stateVerifyUuidHash(state, h)) {
2257             state->bail = 1;
2258         }
2259     } else if (h_stateVerifyAddrHash(state, h, h->host, h->port)) {
2260         state->bail = 1;
2261     }
2262
2263     if (cb_stateVerifyHCBList(state, h)) {
2264         state->bail = 1;
2265     }
2266
2267  done:
2268     return held;
2269 }
2270
2271 static int
2272 h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port)
2273 {
2274     int ret = 0, found = 0;
2275     struct host *host = NULL;
2276     struct h_hashChain *chain;
2277     int index = h_HashIndex(addr);
2278     char tmp[16];
2279     int chain_len = 0;
2280
2281     for (chain = hostHashTable[index]; chain; chain = chain->next) {
2282         host = chain->hostPtr;
2283         if (host == NULL) {
2284             afs_inet_ntoa_r(addr, tmp);
2285             ViceLog(0, ("h_stateVerifyAddrHash: error: addr hash chain has NULL host ptr (lookup addr %s)\n", tmp));
2286             ret = 1;
2287             goto done;
2288         }
2289         if ((chain->addr == addr) && (chain->port == port)) {
2290             if (host != h) {
2291                 ViceLog(0, ("h_stateVerifyAddrHash: warning: addr hash entry points to different host struct (%d, %d)\n", 
2292                             h->index, host->index));
2293                 state->flags.warnings_generated = 1;
2294             }
2295             found = 1;
2296             break;
2297         }
2298         if (chain_len > FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN) {
2299             ViceLog(0, ("h_stateVerifyAddrHash: error: hash chain length exceeds %d; assuming there's a loop\n",
2300                         FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN));
2301             ret = 1;
2302             goto done;
2303         }
2304         chain_len++;
2305     }
2306
2307     if (!found) {
2308         afs_inet_ntoa_r(addr, tmp);
2309         if (state->mode == FS_STATE_LOAD_MODE) {
2310             ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s not found in hash\n", tmp));
2311             ret = 1;
2312             goto done;
2313         } else {
2314             ViceLog(0, ("h_stateVerifyAddrHash: warning: addr %s not found in hash\n", tmp));
2315             state->flags.warnings_generated = 1;
2316         }
2317     }
2318
2319  done:
2320     return ret;
2321 }
2322
2323 static int
2324 h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h)
2325 {
2326     int ret = 0, found = 0;
2327     struct host *host = NULL;
2328     struct h_hashChain *chain;
2329     afsUUID * uuidp = &h->interface->uuid;
2330     int index = h_UuidHashIndex(uuidp);
2331     char tmp[40];
2332     int chain_len = 0;
2333
2334     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
2335         host = chain->hostPtr;
2336         if (host == NULL) {
2337             afsUUID_to_string(uuidp, tmp, sizeof(tmp));
2338             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid hash chain has NULL host ptr (lookup uuid %s)\n", tmp));
2339             ret = 1;
2340             goto done;
2341         }
2342         if (host->interface &&
2343             afs_uuid_equal(&host->interface->uuid, uuidp)) {
2344             if (host != h) {
2345                 ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid hash entry points to different host struct (%d, %d)\n", 
2346                             h->index, host->index));
2347                 state->flags.warnings_generated = 1;
2348             }
2349             found = 1;
2350             goto done;
2351         }
2352         if (chain_len > FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN) {
2353             ViceLog(0, ("h_stateVerifyUuidHash: error: hash chain length exceeds %d; assuming there's a loop\n",
2354                         FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN));
2355             ret = 1;
2356             goto done;
2357         }
2358         chain_len++;
2359     }
2360
2361     if (!found) {
2362         afsUUID_to_string(uuidp, tmp, sizeof(tmp));
2363         if (state->mode == FS_STATE_LOAD_MODE) {
2364             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid %s not found in hash\n", tmp));
2365             ret = 1;
2366             goto done;
2367         } else {
2368             ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid %s not found in hash\n", tmp));
2369             state->flags.warnings_generated = 1;
2370         }
2371     }
2372
2373  done:
2374     return ret;
2375 }
2376
2377 /* create the host state header structure */
2378 static int
2379 h_stateFillHeader(struct host_state_header * hdr)
2380 {
2381     hdr->stamp.magic = HOST_STATE_MAGIC;
2382     hdr->stamp.version = HOST_STATE_VERSION;
2383 }
2384
2385 /* check the contents of the host state header structure */
2386 static int
2387 h_stateCheckHeader(struct host_state_header * hdr)
2388 {
2389     int ret=0;
2390
2391     if (hdr->stamp.magic != HOST_STATE_MAGIC) {
2392         ViceLog(0, ("check_host_state_header: invalid state header\n"));
2393         ret = 1;
2394     }
2395     else if (hdr->stamp.version != HOST_STATE_VERSION) {
2396         ViceLog(0, ("check_host_state_header: unknown version number\n"));
2397         ret = 1;
2398     }
2399     return ret;
2400 }
2401
2402 /* allocate the host id mapping table */
2403 static int
2404 h_stateAllocMap(struct fs_dump_state * state)
2405 {
2406     state->h_map.len = state->h_hdr->index_max + 1;
2407     state->h_map.entries = (struct idx_map_entry_t *)
2408         calloc(state->h_map.len, sizeof(struct idx_map_entry_t));
2409     return (state->h_map.entries != NULL) ? 0 : 1;
2410 }
2411
2412 /* function called by h_Enumerate to save a host to disk */
2413 static int
2414 h_stateSaveHost(register struct host * host, int held, struct fs_dump_state * state)
2415 {
2416     int i, if_len=0, hcps_len=0;
2417     struct hostDiskEntry hdsk;
2418     struct host_state_entry_header hdr;
2419     struct Interface * ifp = NULL;
2420     afs_int32 * hcps = NULL;
2421     struct iovec iov[4];
2422     int iovcnt = 2;
2423
2424     memset(&hdr, 0, sizeof(hdr));
2425
2426     if (state->h_hdr->index_max < host->index) {
2427         state->h_hdr->index_max = host->index;
2428     }
2429
2430     h_hostToDiskEntry_r(host, &hdsk);
2431     if (host->interface) {
2432         if_len = sizeof(struct Interface) + 
2433             ((host->interface->numberOfInterfaces-1) * sizeof(struct AddrPort));
2434         ifp = (struct Interface *) malloc(if_len);
2435         assert(ifp != NULL);
2436         memcpy(ifp, host->interface, if_len);
2437         hdr.interfaces = host->interface->numberOfInterfaces;
2438         iov[iovcnt].iov_base = (char *) ifp;
2439         iov[iovcnt].iov_len = if_len;
2440         iovcnt++;
2441     }
2442     if (host->hcps.prlist_val) {
2443         hdr.hcps = host->hcps.prlist_len;
2444         hcps_len = hdr.hcps * sizeof(afs_int32);
2445         hcps = (afs_int32 *) malloc(hcps_len);
2446         assert(hcps != NULL);
2447         memcpy(hcps, host->hcps.prlist_val, hcps_len);
2448         iov[iovcnt].iov_base = (char *) hcps;
2449         iov[iovcnt].iov_len = hcps_len;
2450         iovcnt++;
2451     }
2452
2453     if (hdsk.index > state->h_hdr->index_max)
2454         state->h_hdr->index_max = hdsk.index;
2455
2456     hdr.len = sizeof(struct host_state_entry_header) + 
2457         sizeof(struct hostDiskEntry) + if_len + hcps_len;
2458     hdr.magic = HOST_STATE_ENTRY_MAGIC;
2459
2460     iov[0].iov_base = (char *) &hdr;
2461     iov[0].iov_len = sizeof(hdr);
2462     iov[1].iov_base = (char *) &hdsk;
2463     iov[1].iov_len = sizeof(struct hostDiskEntry);
2464     
2465     if (fs_stateWriteV(state, iov, iovcnt)) {
2466         ViceLog(0, ("h_stateSaveHost: failed to save host %d", host->index));
2467         state->bail = 1;
2468     }
2469
2470     fs_stateIncEOF(state, hdr.len);
2471
2472     state->h_hdr->records++;
2473
2474  done:
2475     if (ifp)
2476         free(ifp);
2477     if (hcps)
2478         free(hcps);
2479     if (state->bail) {
2480         return H_ENUMERATE_BAIL(held);
2481     }
2482     return held;
2483 }
2484
2485 /* restores a host from disk */
2486 static int
2487 h_stateRestoreHost(struct fs_dump_state * state)
2488 {
2489     int ifp_len=0, hcps_len=0, bail=0;
2490     struct host_state_entry_header hdr;
2491     struct hostDiskEntry hdsk;
2492     struct host *host = NULL;
2493     struct Interface *ifp = NULL;
2494     afs_int32 * hcps = NULL;
2495     struct iovec iov[3];
2496     int iovcnt = 1;
2497
2498     if (fs_stateRead(state, &hdr, sizeof(hdr))) {
2499         ViceLog(0, ("h_stateRestoreHost: failed to read host entry header from dump file '%s'\n",
2500                     state->fn));
2501         bail = 1;
2502         goto done;
2503     }
2504
2505     if (hdr.magic != HOST_STATE_ENTRY_MAGIC) {
2506         ViceLog(0, ("h_stateRestoreHost: fileserver state dump file '%s' is corrupt.\n",
2507                     state->fn));
2508         bail = 1;
2509         goto done;
2510     }
2511
2512     iov[0].iov_base = (char *) &hdsk;
2513     iov[0].iov_len = sizeof(struct hostDiskEntry);
2514
2515     if (hdr.interfaces) {
2516         ifp_len = sizeof(struct Interface) +
2517             ((hdr.interfaces-1) * sizeof(struct AddrPort));
2518         ifp = (struct Interface *) malloc(ifp_len);
2519         assert(ifp != NULL);
2520         iov[iovcnt].iov_base = (char *) ifp;
2521         iov[iovcnt].iov_len = ifp_len;
2522         iovcnt++;
2523     }
2524     if (hdr.hcps) {
2525         hcps_len = hdr.hcps * sizeof(afs_int32);
2526         hcps = (afs_int32 *) malloc(hcps_len);
2527         assert(hcps != NULL);
2528         iov[iovcnt].iov_base = (char *) hcps;
2529         iov[iovcnt].iov_len = hcps_len;
2530         iovcnt++;
2531     }
2532
2533     if ((ifp_len + hcps_len + sizeof(hdsk) + sizeof(hdr)) != hdr.len) {
2534         ViceLog(0, ("h_stateRestoreHost: host entry header length fields are inconsistent\n"));
2535         bail = 1;
2536         goto done;
2537     }
2538
2539     if (fs_stateReadV(state, iov, iovcnt)) {
2540         ViceLog(0, ("h_stateRestoreHost: failed to read host entry\n"));
2541         bail = 1;
2542         goto done;
2543     }
2544
2545     if (!hdr.hcps && hdsk.hcps_valid) {
2546         /* valid, zero-length host cps ; does this ever happen? */
2547         hcps = (afs_int32 *) malloc(sizeof(afs_int32));
2548         assert(hcps != NULL);
2549     }
2550
2551     host = GetHT();
2552     assert(host != NULL);
2553
2554     if (ifp) {
2555         host->interface = ifp;
2556     }
2557     if (hcps) {
2558         host->hcps.prlist_val = hcps;
2559         host->hcps.prlist_len = hdr.hcps;
2560     }
2561
2562     h_diskEntryToHost_r(&hdsk, host);
2563     h_SetupCallbackConn_r(host);
2564
2565     if (ifp) {
2566         int i;
2567         for (i = ifp->numberOfInterfaces-1; i >= 0; i--) {
2568             h_AddHostToHashTable_r(ifp->interface[i].addr, 
2569                                    ifp->interface[i].port, host);
2570         }
2571         h_AddHostToUuidHashTable_r(&ifp->uuid, host);
2572     } else {
2573         h_AddHostToHashTable_r(host->host, host->port, host);
2574     }
2575     h_InsertList_r(host);
2576
2577     /* setup host id map entry */
2578     state->h_map.entries[hdsk.index].old_idx = hdsk.index;
2579     state->h_map.entries[hdsk.index].new_idx = host->index;
2580
2581  done:
2582     if (bail) {
2583         if (ifp)
2584             free(ifp);
2585         if (hcps)
2586             free(hcps);
2587     }
2588     return bail;
2589 }
2590
2591 /* serialize a host structure to disk */
2592 static void
2593 h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out)
2594 {
2595     out->host = in->host;
2596     out->port = in->port;
2597     out->hostFlags = in->hostFlags;
2598     out->Console = in->Console;
2599     out->hcpsfailed = in->hcpsfailed;
2600     out->LastCall = in->LastCall;
2601     out->ActiveCall = in->ActiveCall;
2602     out->cpsCall = in->cpsCall;
2603     out->cblist = in->cblist;
2604 #ifdef FS_STATS_DETAILED
2605     out->InSameNetwork = in->InSameNetwork;
2606 #endif
2607
2608     /* special fields we save, but are not memcpy'd back on restore */
2609     out->index = in->index;
2610     out->hcps_len = in->hcps.prlist_len;
2611     out->hcps_valid = (in->hcps.prlist_val == NULL) ? 0 : 1;
2612 }
2613
2614 /* restore a host structure from disk */
2615 static void
2616 h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out)
2617 {
2618     out->host = in->host;
2619     out->port = in->port;
2620     out->hostFlags = in->hostFlags;
2621     out->Console = in->Console;
2622     out->hcpsfailed = in->hcpsfailed;
2623     out->LastCall = in->LastCall;
2624     out->ActiveCall = in->ActiveCall;
2625     out->cpsCall = in->cpsCall;
2626     out->cblist = in->cblist;
2627 #ifdef FS_STATS_DETAILED
2628     out->InSameNetwork = in->InSameNetwork;
2629 #endif
2630 }
2631
2632 /* index translation routines */
2633 int
2634 h_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
2635 {
2636     int ret = 0;
2637
2638     /* hosts use a zero-based index, so old==0 is valid */
2639
2640     if (old >= state->h_map.len) {
2641         ViceLog(0, ("h_OldToNew: index %d is out of range\n", old));
2642         ret = 1;
2643     } else if (state->h_map.entries[old].old_idx != old) { /* sanity check */
2644         ViceLog(0, ("h_OldToNew: index %d points to an invalid host record\n", old));
2645         ret = 1;
2646     } else {
2647         *new = state->h_map.entries[old].new_idx;
2648     }
2649
2650  done:
2651     return ret;
2652 }
2653 #endif /* AFS_DEMAND_ATTACH_FS */
2654
2655
2656 /*
2657  * This counts the number of workstations, the number of active workstations,
2658  * and the number of workstations declared "down" (i.e. not heard from
2659  * recently).  An active workstation has received a call since the cutoff
2660  * time argument passed.
2661  */
2662 void
2663 h_GetWorkStats(int *nump, int *activep, int *delp, afs_int32 cutofftime)
2664 {
2665     register struct host *host;
2666     register int num = 0, active = 0, del = 0;
2667
2668     H_LOCK;
2669     for (host = hostList; host; host = host->next) {
2670         if (!(host->hostFlags & HOSTDELETED)) {
2671             num++;
2672             if (host->ActiveCall > cutofftime)
2673                 active++;
2674             if (host->hostFlags & VENUSDOWN)
2675                 del++;
2676         }
2677     }
2678     H_UNLOCK;
2679     if (nump)
2680         *nump = num;
2681     if (activep)
2682         *activep = active;
2683     if (delp)
2684         *delp = del;
2685
2686 }                               /*h_GetWorkStats */
2687
2688
2689 /*------------------------------------------------------------------------
2690  * PRIVATE h_ClassifyAddress
2691  *
2692  * Description:
2693  *      Given a target IP address and a candidate IP address (both
2694  *      in host byte order), classify the candidate into one of three
2695  *      buckets in relation to the target by bumping the counters passed
2696  *      in as parameters.
2697  *
2698  * Arguments:
2699  *      a_targetAddr       : Target address.
2700  *      a_candAddr         : Candidate address.
2701  *      a_sameNetOrSubnetP : Ptr to counter to bump when the two
2702  *                           addresses are either in the same network
2703  *                           or the same subnet.
2704  *      a_diffSubnetP      : ...when the candidate is in a different
2705  *                           subnet.
2706  *      a_diffNetworkP     : ...when the candidate is in a different
2707  *                           network.
2708  *
2709  * Returns:
2710  *      Nothing.
2711  *
2712  * Environment:
2713  *      The target and candidate addresses are both in host byte
2714  *      order, NOT network byte order, when passed in.
2715  *
2716  * Side Effects:
2717  *      As advertised.
2718  *------------------------------------------------------------------------*/
2719
2720 static void
2721 h_ClassifyAddress(afs_uint32 a_targetAddr, afs_uint32 a_candAddr,
2722                   afs_int32 * a_sameNetOrSubnetP, afs_int32 * a_diffSubnetP,
2723                   afs_int32 * a_diffNetworkP)
2724 {                               /*h_ClassifyAddress */
2725
2726     afs_uint32 targetNet;
2727     afs_uint32 targetSubnet;
2728     afs_uint32 candNet;
2729     afs_uint32 candSubnet;
2730
2731     /*
2732      * Put bad values into the subnet info to start with.
2733      */
2734     targetSubnet = (afs_uint32) 0;
2735     candSubnet = (afs_uint32) 0;
2736
2737     /*
2738      * Pull out the network and subnetwork numbers from the target
2739      * and candidate addresses.  We can short-circuit this whole
2740      * affair if the target and candidate addresses are not of the
2741      * same class.
2742      */
2743     if (IN_CLASSA(a_targetAddr)) {
2744         if (!(IN_CLASSA(a_candAddr))) {
2745             (*a_diffNetworkP)++;
2746             return;
2747         }
2748         targetNet = a_targetAddr & IN_CLASSA_NET;
2749         candNet = a_candAddr & IN_CLASSA_NET;
2750         if (IN_SUBNETA(a_targetAddr))
2751             targetSubnet = a_targetAddr & IN_CLASSA_SUBNET;
2752         if (IN_SUBNETA(a_candAddr))
2753             candSubnet = a_candAddr & IN_CLASSA_SUBNET;
2754     } else if (IN_CLASSB(a_targetAddr)) {
2755         if (!(IN_CLASSB(a_candAddr))) {
2756             (*a_diffNetworkP)++;
2757             return;
2758         }
2759         targetNet = a_targetAddr & IN_CLASSB_NET;
2760         candNet = a_candAddr & IN_CLASSB_NET;
2761         if (IN_SUBNETB(a_targetAddr))
2762             targetSubnet = a_targetAddr & IN_CLASSB_SUBNET;
2763         if (IN_SUBNETB(a_candAddr))
2764             candSubnet = a_candAddr & IN_CLASSB_SUBNET;
2765     } /*Class B target */
2766     else if (IN_CLASSC(a_targetAddr)) {
2767         if (!(IN_CLASSC(a_candAddr))) {
2768             (*a_diffNetworkP)++;
2769             return;
2770         }
2771         targetNet = a_targetAddr & IN_CLASSC_NET;
2772         candNet = a_candAddr & IN_CLASSC_NET;
2773
2774         /*
2775          * Note that class C addresses can't have subnets,
2776          * so we leave the defaults untouched.
2777          */
2778     } /*Class C target */
2779     else {
2780         targetNet = a_targetAddr;
2781         candNet = a_candAddr;
2782     }                           /*Class D address */
2783
2784     /*
2785      * Now, simply compare the extracted net and subnet values for
2786      * the two addresses (which at this point are known to be of the
2787      * same class)
2788      */
2789     if (targetNet == candNet) {
2790         if (targetSubnet == candSubnet)
2791             (*a_sameNetOrSubnetP)++;
2792         else
2793             (*a_diffSubnetP)++;
2794     } else
2795         (*a_diffNetworkP)++;
2796
2797 }                               /*h_ClassifyAddress */
2798
2799
2800 /*------------------------------------------------------------------------
2801  * EXPORTED h_GetHostNetStats
2802  *
2803  * Description:
2804  *      Iterate through the host table, and classify each (non-deleted)
2805  *      host entry into ``proximity'' categories (same net or subnet,
2806  *      different subnet, different network).
2807  *
2808  * Arguments:
2809  *      a_numHostsP        : Set to total number of (non-deleted) hosts.
2810  *      a_sameNetOrSubnetP : Set to # hosts on same net/subnet as server.
2811  *      a_diffSubnetP      : Set to # hosts on diff subnet as server.
2812  *      a_diffNetworkP     : Set to # hosts on diff network as server.
2813  *
2814  * Returns:
2815  *      Nothing.
2816  *
2817  * Environment:
2818  *      We only count non-deleted hosts.  The storage pointed to by our
2819  *      parameters is zeroed upon entry.
2820  *
2821  * Side Effects:
2822  *      As advertised.
2823  *------------------------------------------------------------------------*/
2824
2825 void
2826 h_GetHostNetStats(afs_int32 * a_numHostsP, afs_int32 * a_sameNetOrSubnetP,
2827                   afs_int32 * a_diffSubnetP, afs_int32 * a_diffNetworkP)
2828 {                               /*h_GetHostNetStats */
2829
2830     register struct host *hostP;        /*Ptr to current host entry */
2831     register afs_uint32 currAddr_HBO;   /*Curr host addr, host byte order */
2832
2833     /*
2834      * Clear out the storage pointed to by our parameters.
2835      */
2836     *a_numHostsP = (afs_int32) 0;
2837     *a_sameNetOrSubnetP = (afs_int32) 0;
2838     *a_diffSubnetP = (afs_int32) 0;
2839     *a_diffNetworkP = (afs_int32) 0;
2840
2841     H_LOCK;
2842     for (hostP = hostList; hostP; hostP = hostP->next) {
2843         if (!(hostP->hostFlags & HOSTDELETED)) {
2844             /*
2845              * Bump the number of undeleted host entries found.
2846              * In classifying the current entry's address, make
2847              * sure to first convert to host byte order.
2848              */
2849             (*a_numHostsP)++;
2850             currAddr_HBO = (afs_uint32) ntohl(hostP->host);
2851             h_ClassifyAddress(FS_HostAddr_HBO, currAddr_HBO,
2852                               a_sameNetOrSubnetP, a_diffSubnetP,
2853                               a_diffNetworkP);
2854         }                       /*Only look at non-deleted hosts */
2855     }                           /*For each host record hashed to this index */
2856     H_UNLOCK;
2857 }                               /*h_GetHostNetStats */
2858
2859 static afs_uint32 checktime;
2860 static afs_uint32 clientdeletetime;
2861 static struct AFSFid zerofid;
2862
2863
2864 /*
2865  * XXXX: This routine could use Multi-Rx to avoid serializing the timeouts.
2866  * Since it can serialize them, and pile up, it should be a separate LWP
2867  * from other events.
2868  */
2869 static int
2870 CheckHost(register struct host *host, int held)
2871 {
2872     register struct client *client;
2873     struct rx_connection *cb_conn = NULL;
2874     int code;
2875
2876 #ifdef AFS_DEMAND_ATTACH_FS
2877     /* kill the checkhost lwp ASAP during shutdown */
2878     FS_STATE_RDLOCK;
2879     if (fs_state.mode == FS_MODE_SHUTDOWN) {
2880         FS_STATE_UNLOCK;
2881         return H_ENUMERATE_BAIL(held);
2882     }
2883     FS_STATE_UNLOCK;
2884 #endif
2885
2886     /* Host is held by h_Enumerate */
2887     H_LOCK;
2888     for (client = host->FirstClient; client; client = client->next) {
2889         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
2890             client->deleted = 1;
2891             host->hostFlags |= CLIENTDELETED;
2892         }
2893     }
2894     if (host->LastCall < checktime) {
2895         h_Lock_r(host);
2896         if (!(host->hostFlags & HOSTDELETED)) {
2897             cb_conn = host->callback_rxcon;
2898             rx_GetConnection(cb_conn);
2899             if (host->LastCall < clientdeletetime) {
2900                 host->hostFlags |= HOSTDELETED;
2901                 if (!(host->hostFlags & VENUSDOWN)) {
2902                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
2903                     if (host->interface) {
2904                         H_UNLOCK;
2905                         code =
2906                             RXAFSCB_InitCallBackState3(cb_conn,
2907                                                        &FS_HostUUID);
2908                         H_LOCK;
2909                     } else {
2910                         H_UNLOCK;
2911                         code =
2912                             RXAFSCB_InitCallBackState(cb_conn);
2913                         H_LOCK;
2914                     }
2915                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
2916                     if (code) {
2917                         char hoststr[16];
2918                         (void)afs_inet_ntoa_r(host->host, hoststr);
2919                         ViceLog(0,
2920                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
2921                                  hoststr, ntohs(host->port)));
2922                         host->hostFlags |= VENUSDOWN;
2923                     }
2924                     /* Note:  it's safe to delete hosts even if they have call
2925                      * back state, because break delayed callbacks (called when a
2926                      * message is received from the workstation) will always send a 
2927                      * break all call backs to the workstation if there is no
2928                      *callback.
2929                      */
2930                 }
2931             } else {
2932                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
2933                     char hoststr[16];
2934                     (void)afs_inet_ntoa_r(host->host, hoststr);
2935                     if (host->interface) {
2936                         afsUUID uuid = host->interface->uuid;
2937                         H_UNLOCK;
2938                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
2939                         H_LOCK;
2940                         if (code) {
2941                             if (MultiProbeAlternateAddress_r(host)) {
2942                                 ViceLog(0,("CheckHost: Probing all interfaces of host %s:%d failed, code %d\n",
2943                                             hoststr, ntohs(host->port), code));
2944                                 host->hostFlags |= VENUSDOWN;
2945                             }
2946                         }
2947                     } else {
2948                         H_UNLOCK;
2949                         code = RXAFSCB_Probe(cb_conn);
2950                         H_LOCK;
2951                         if (code) {
2952                             ViceLog(0,
2953                                     ("CheckHost: Probe failed for host %s:%d, code %d\n", 
2954                                      hoststr, ntohs(host->port), code));
2955                             host->hostFlags |= VENUSDOWN;
2956                         }
2957                     }
2958                 }
2959             }
2960             H_UNLOCK;
2961             rx_PutConnection(cb_conn);
2962             cb_conn=NULL;
2963             H_LOCK;
2964         }
2965         h_Unlock_r(host);
2966     }
2967     H_UNLOCK;
2968     return held;
2969
2970 }                               /*CheckHost */
2971
2972
2973 /*
2974  * Set VenusDown for any hosts that have not had a call in 15 minutes and
2975  * don't respond to a probe.  Note that VenusDown can only be cleared if
2976  * a message is received from the host (see ServerLWP in file.c).
2977  * Delete hosts that have not had any calls in 1 hour, clients that
2978  * have not had any calls in 15 minutes.
2979  *
2980  * This routine is called roughly every 5 minutes.
2981  */
2982 void
2983 h_CheckHosts(void)
2984 {
2985     afs_uint32 now = FT_ApproxTime();
2986
2987     memset((char *)&zerofid, 0, sizeof(zerofid));
2988     /*
2989      * Send a probe to the workstation if it hasn't been heard from in
2990      * 15 minutes
2991      */
2992     checktime = now - 15 * 60;
2993     clientdeletetime = now - 120 * 60;  /* 2 hours ago */
2994     h_Enumerate(CheckHost, NULL);
2995
2996 }                               /*h_CheckHosts */
2997
2998 /*
2999  * This is called with host locked and held. At this point, the
3000  * hostHashTable should not have any entries for the alternate
3001  * interfaces. This function has to insert these entries in the
3002  * hostHashTable.
3003  *
3004  * The addresses in the interfaceAddr list are in host byte order.
3005  */
3006 int
3007 initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
3008 {
3009     int i, j;
3010     int number, count;
3011     afs_uint32 myAddr;
3012     afs_uint16 myPort;
3013     int found;
3014     struct Interface *interface;
3015     char hoststr[16];
3016
3017     assert(host);
3018     assert(interf);
3019
3020     number = interf->numberOfInterfaces;
3021     myAddr = host->host;        /* current interface address */
3022     myPort = host->port;        /* current port */
3023
3024     ViceLog(125,
3025             ("initInterfaceAddr : host %s:%d numAddr %d\n", 
3026               afs_inet_ntoa_r(myAddr, hoststr), ntohs(myPort), number));
3027
3028     /* validation checks */
3029     if (number < 0 || number > AFS_MAX_INTERFACE_ADDR) {
3030         ViceLog(0,
3031                 ("Invalid number of alternate addresses is %d\n", number));
3032         return -1;
3033     }
3034
3035     /*
3036      * Convert IP addresses to network byte order, and remove for
3037      * duplicate IP addresses from the interface list.
3038      */
3039     for (i = 0, count = 0, found = 0; i < number; i++) {
3040         interf->addr_in[i] = htonl(interf->addr_in[i]);
3041         for (j = 0; j < count; j++) {
3042             if (interf->addr_in[j] == interf->addr_in[i])
3043                 break;
3044         }
3045         if (j == count) {
3046             interf->addr_in[count] = interf->addr_in[i];
3047             if (interf->addr_in[count] == myAddr)
3048                 found = 1;
3049             count++;
3050         }
3051     }
3052
3053     /*
3054      * Allocate and initialize an interface structure for this host.
3055      */
3056     if (found) {
3057         interface = (struct Interface *)
3058             malloc(sizeof(struct Interface) +
3059                    (sizeof(struct AddrPort) * (count - 1)));
3060         if (!interface) {
3061             ViceLog(0, ("Failed malloc in initInterfaceAddr_r\n"));
3062             assert(0);
3063         }
3064         interface->numberOfInterfaces = count;
3065     } else {
3066         interface = (struct Interface *)
3067             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * count));
3068         assert(interface);
3069         interface->numberOfInterfaces = count + 1;
3070         interface->interface[count].addr = myAddr;
3071         interface->interface[count].port = myPort;
3072     }
3073     interface->uuid = interf->uuid;
3074     for (i = 0; i < count; i++) {
3075         interface->interface[i].addr = interf->addr_in[i];
3076         /* We store the port as 7001 because the addresses reported by 
3077          * TellMeAboutYourself and WhoAreYou RPCs are only valid if they
3078          * are coming from fully connected hosts (no NAT/PATs)
3079          */
3080         interface->interface[i].port = htons(7001);
3081     }
3082
3083     assert(!host->interface);
3084     host->interface = interface;
3085
3086     for (i = 0; i < host->interface->numberOfInterfaces; i++) {
3087         ViceLog(125, ("--- alt address %s:%d\n", 
3088                        afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
3089                        ntohs(host->interface->interface[i].port)));
3090     }
3091
3092     return 0;
3093 }
3094
3095 /* deleted a HashChain structure for this address and host */
3096 /* returns 1 on success */
3097 static int
3098 h_DeleteHostFromHashTableByAddr_r(afs_uint32 addr, afs_uint16 port, struct host *host)
3099 {
3100     int flag;
3101     register struct h_hashChain **hp, *th;
3102
3103     for (hp = &hostHashTable[h_HashIndex(addr)]; (th = *hp);) {
3104         assert(th->hostPtr);
3105         if (th->hostPtr == host && th->addr == addr && th->port == port) {
3106             *hp = th->next;
3107             free(th);
3108             flag = 1;
3109             break;
3110         } else {
3111             hp = &th->next;
3112         }
3113     }
3114     return flag;
3115 }
3116
3117
3118 /*
3119 ** prints out all alternate interface address for the host. The 'level'
3120 ** parameter indicates what level of debugging sets this output
3121 */
3122 void
3123 printInterfaceAddr(struct host *host, int level)
3124 {
3125     int i, number;
3126     char hoststr[16];
3127
3128     if (host->interface) {
3129         /* check alternate addresses */
3130         number = host->interface->numberOfInterfaces;
3131         assert(number > 0);
3132         for (i = 0; i < number; i++)
3133             ViceLog(level, ("%s:%d ", afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
3134                              ntohs(host->interface->interface[i].port)));
3135     }
3136     ViceLog(level, ("\n"));
3137 }