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