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