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