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