viced: fix log message for MapName_r
[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((void *)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 char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
2185 int  num_lrealms = -1;
2186
2187 /* not reentrant */
2188 void
2189 h_InitHostPackage(void)
2190 {
2191     memset(&nulluuid, 0, sizeof(afsUUID));
2192     afsconf_GetLocalCell(confDir, localcellname, PR_MAXNAMELEN);
2193     if (num_lrealms == -1) {
2194         int i;
2195         for (i=0; i<AFS_NUM_LREALMS; i++) {
2196             if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
2197                 break;
2198         }
2199
2200         if (i == 0) {
2201             ViceLog(0,
2202                     ("afs_krb_get_lrealm failed, using %s.\n",
2203                      localcellname));
2204             strncpy(local_realms[0], localcellname, AFS_REALM_SZ);
2205             num_lrealms = i =1;
2206         } else {
2207             num_lrealms = i;
2208         }
2209
2210         /* initialize the rest of the local realms to nullstring for debugging */
2211         for (; i<AFS_NUM_LREALMS; i++)
2212             local_realms[i][0] = '\0';
2213     }
2214     rxcon_ident_key = rx_KeyCreate((rx_destructor_t) free);
2215     rxcon_client_key = rx_KeyCreate((rx_destructor_t) 0);
2216     MUTEX_INIT(&host_glock_mutex, "host glock", MUTEX_DEFAULT, 0);
2217 }
2218
2219 static int
2220 MapName_r(char *aname, char *acell, afs_int32 * aval)
2221 {
2222     namelist lnames;
2223     idlist lids;
2224     afs_int32 code;
2225     afs_int32 anamelen, cnamelen;
2226     int foreign = 0;
2227     char *tname;
2228
2229     anamelen = strlen(aname);
2230     if (anamelen >= PR_MAXNAMELEN)
2231         return -1;              /* bad name -- caller interprets this as anonymous, but retries later */
2232
2233     lnames.namelist_len = 1;
2234     lnames.namelist_val = (prname *) aname;     /* don't malloc in the common case */
2235     lids.idlist_len = 0;
2236     lids.idlist_val = NULL;
2237
2238     cnamelen = strlen(acell);
2239     if (cnamelen) {
2240         if (afs_is_foreign_ticket_name(aname, NULL, acell, localcellname)) {
2241             ViceLog(2,
2242                     ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealms={%s,%s,%s,%s}\n",
2243                     acell, localcellname, local_realms[0],local_realms[1],local_realms[2],local_realms[3]));
2244             if ((anamelen + cnamelen + 1) >= PR_MAXNAMELEN) {
2245                 ViceLog(2,
2246                         ("MapName: Name too long, using AnonymousID for %s@%s\n",
2247                          aname, acell));
2248                 *aval = AnonymousID;
2249                 return 0;
2250             }
2251             foreign = 1;        /* attempt cross-cell authentication */
2252             tname = (char *)malloc(PR_MAXNAMELEN);
2253             if (!tname) {
2254                 ViceLogThenPanic(0, ("Failed malloc in MapName_r\n"));
2255             }
2256             strcpy(tname, aname);
2257             tname[anamelen] = '@';
2258             strcpy(tname + anamelen + 1, acell);
2259             lnames.namelist_val = (prname *) tname;
2260         }
2261     }
2262
2263     H_UNLOCK;
2264     code = hpr_NameToId(&lnames, &lids);
2265     H_LOCK;
2266     if (code == 0) {
2267         if (lids.idlist_val) {
2268             *aval = lids.idlist_val[0];
2269             if (*aval == AnonymousID) {
2270                 ViceLog(2,
2271                         ("MapName: NameToId on %s returns anonymousID\n",
2272                          lnames.namelist_val[0]));
2273             }
2274             free(lids.idlist_val);      /* return parms are not malloced in stub if server proc aborts */
2275         } else {
2276             ViceLog(0,
2277                     ("MapName: NameToId on '%s' is unknown\n",
2278                      lnames.namelist_val[0]));
2279             code = -1;
2280         }
2281     }
2282
2283     if (foreign) {
2284         free(lnames.namelist_val);      /* We allocated this above, so we must free it now. */
2285     }
2286     return code;
2287 }
2288
2289 /*MapName*/
2290
2291
2292 /* NOTE: this returns the client with a Write lock and a refCount */
2293 struct client *
2294 h_ID2Client(afs_int32 vid)
2295 {
2296     struct client *client;
2297     struct host *host;
2298     int count;
2299
2300     H_LOCK;
2301     for (count = 0, host = hostList; host && count < hostCount; host = host->next, count++) {
2302         if (host->hostFlags & HOSTDELETED)
2303             continue;
2304         for (client = host->FirstClient; client; client = client->next) {
2305             if (!client->deleted && client->ViceId == vid) {
2306                 client->refCount++;
2307                 H_UNLOCK;
2308                 ObtainWriteLock(&client->lock);
2309                 return client;
2310             }
2311         }
2312     }
2313     if (count != hostCount) {
2314         ViceLog(0, ("h_ID2Client found %d of %d hosts\n", count, hostCount));
2315     } else if (host != NULL) {
2316         ViceLog(0, ("h_ID2Client found more than %d hosts\n", hostCount));
2317         ShutDownAndCore(PANIC);
2318     }
2319
2320     H_UNLOCK;
2321     return NULL;
2322 }
2323
2324 /*
2325  * Called by the server main loop.  Returns a h_Held client, which must be
2326  * released later the main loop.  Allocates a client if the matching one
2327  * isn't around. The client is returned with its reference count incremented
2328  * by one. The caller must call h_ReleaseClient_r when finished with
2329  * the client.
2330  *
2331  * The refCount on client->host is returned incremented.  h_ReleaseClient_r
2332  * does not decrement the refCount on client->host.
2333  */
2334 struct client *
2335 h_FindClient_r(struct rx_connection *tcon)
2336 {
2337     struct client *client;
2338     struct host *host = NULL;
2339     struct client *oldClient;
2340     afs_int32 viceid = 0;
2341     afs_int32 expTime;
2342     afs_int32 code;
2343     int authClass;
2344 #if (64-MAXKTCNAMELEN)
2345     ticket name length != 64
2346 #endif
2347     char tname[64];
2348     char tinst[64];
2349     char uname[PR_MAXNAMELEN];
2350     char tcell[MAXKTCREALMLEN];
2351     int fail = 0;
2352     int created = 0;
2353
2354     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2355     if (client && client->sid == rx_GetConnectionId(tcon)
2356         && client->VenusEpoch == rx_GetConnectionEpoch(tcon)
2357         && !(client->host->hostFlags & HOSTDELETED)
2358         && !client->deleted) {
2359
2360         client->refCount++;
2361         h_Hold_r(client->host);
2362         if (client->prfail != 2) {
2363             /* Could add shared lock on client here */
2364             /* note that we don't have to lock entry in this path to
2365              * ensure CPS is initialized, since we don't call rx_SetSpecific
2366              * until initialization is done, and we only get here if
2367              * rx_GetSpecific located the client structure.
2368              */
2369             return client;
2370         }
2371         H_UNLOCK;
2372         ObtainWriteLock(&client->lock); /* released at end */
2373         H_LOCK;
2374     } else {
2375         client = NULL;
2376     }
2377
2378     authClass = rx_SecurityClassOf((struct rx_connection *)tcon);
2379     ViceLog(5,
2380             ("FindClient: authenticating connection: authClass=%d\n",
2381              authClass));
2382     if (authClass == 1) {
2383         /* A bcrypt tickets, no longer supported */
2384         ViceLog(1, ("FindClient: bcrypt ticket, using AnonymousID\n"));
2385         viceid = AnonymousID;
2386         expTime = 0x7fffffff;
2387     } else if (authClass == 2) {
2388         afs_int32 kvno;
2389
2390         /* kerberos ticket */
2391         code = rxkad_GetServerInfo(tcon, /*level */ 0, (afs_uint32 *)&expTime,
2392                                    tname, tinst, tcell, &kvno);
2393         if (code) {
2394             ViceLog(1, ("Failed to get rxkad ticket info\n"));
2395             viceid = AnonymousID;
2396             expTime = 0x7fffffff;
2397         } else {
2398             int ilen = strlen(tinst);
2399             ViceLog(5,
2400                     ("FindClient: rxkad conn: name=%s,inst=%s,cell=%s,exp=%d,kvno=%d\n",
2401                      tname, tinst, tcell, expTime, kvno));
2402             strncpy(uname, tname, sizeof(uname));
2403             if (ilen) {
2404                 if (strlen(uname) + 1 + ilen >= sizeof(uname)) {
2405                     code = -1;
2406                     goto bad_name;
2407                 }
2408                 strcat(uname, ".");
2409                 strcat(uname, tinst);
2410             }
2411             /* translate the name to a vice id */
2412             code = MapName_r(uname, tcell, &viceid);
2413             if (code) {
2414               bad_name:
2415                 ViceLog(1,
2416                         ("failed to map name=%s, cell=%s -> code=%d\n", uname,
2417                          tcell, code));
2418                 fail = 1;
2419                 viceid = AnonymousID;
2420                 expTime = 0x7fffffff;
2421             }
2422         }
2423     } else {
2424         viceid = AnonymousID;   /* unknown security class */
2425         expTime = 0x7fffffff;
2426     }
2427
2428     if (!client) { /* loop */
2429         host = h_GetHost_r(tcon);       /* Returns with incremented refCount  */
2430
2431         if (!host)
2432             return NULL;
2433
2434     retryfirstclient:
2435         /* First try to find the client structure */
2436         for (client = host->FirstClient; client; client = client->next) {
2437             if (!client->deleted && (client->sid == rx_GetConnectionId(tcon))
2438                 && (client->VenusEpoch == rx_GetConnectionEpoch(tcon))) {
2439                 client->refCount++;
2440                 H_UNLOCK;
2441                 ObtainWriteLock(&client->lock);
2442                 H_LOCK;
2443                 break;
2444             }
2445         }
2446
2447         /* Still no client structure - get one */
2448         if (!client) {
2449             h_Lock_r(host);
2450             if (host->hostFlags & HOSTDELETED) {
2451                 h_Unlock_r(host);
2452                 h_Release_r(host);
2453                 return NULL;
2454             }
2455             /* Retry to find the client structure */
2456             for (client = host->FirstClient; client; client = client->next) {
2457                 if (!client->deleted && (client->sid == rx_GetConnectionId(tcon))
2458                     && (client->VenusEpoch == rx_GetConnectionEpoch(tcon))) {
2459                     h_Unlock_r(host);
2460                     goto retryfirstclient;
2461                 }
2462             }
2463             created = 1;
2464             client = GetCE();
2465             ObtainWriteLock(&client->lock);
2466             client->refCount = 1;
2467             client->host = host;
2468             client->InSameNetwork = host->InSameNetwork;
2469             client->ViceId = viceid;
2470             client->expTime = expTime;  /* rx only */
2471             client->authClass = authClass;      /* rx only */
2472             client->sid = rx_GetConnectionId(tcon);
2473             client->VenusEpoch = rx_GetConnectionEpoch(tcon);
2474             client->CPS.prlist_val = NULL;
2475             client->CPS.prlist_len = 0;
2476             h_Unlock_r(host);
2477         }
2478     }
2479     client->prfail = fail;
2480
2481     if (!(client->CPS.prlist_val) || (viceid != client->ViceId)) {
2482         client->CPS.prlist_len = 0;
2483         if (client->CPS.prlist_val && (client->ViceId != ANONYMOUSID))
2484             free(client->CPS.prlist_val);
2485         client->CPS.prlist_val = NULL;
2486         client->ViceId = viceid;
2487         client->expTime = expTime;
2488
2489         if (viceid == ANONYMOUSID) {
2490             client->CPS.prlist_len = AnonCPS.prlist_len;
2491             client->CPS.prlist_val = AnonCPS.prlist_val;
2492         } else {
2493             H_UNLOCK;
2494             code = hpr_GetCPS(viceid, &client->CPS);
2495             H_LOCK;
2496             if (code) {
2497                 char hoststr[16];
2498                 ViceLog(0,
2499                         ("pr_GetCPS failed(%d) for user %d, host %" AFS_PTR_FMT " (%s:%d)\n",
2500                          code, viceid, client->host,
2501                          afs_inet_ntoa_r(client->host->host,hoststr),
2502                          ntohs(client->host->port)));
2503
2504                 /* Although ubik_Call (called by pr_GetCPS) traverses thru
2505                  * all protection servers and reevaluates things if no
2506                  * sync server or quorum is found we could still end up
2507                  * with one of these errors. In such case we would like to
2508                  * reevaluate the rpc call to find if there's cps for this
2509                  * guy. We treat other errors (except network failures
2510                  * ones - i.e. code < 0) as an indication that there is no
2511                  * CPS for this host.  Ideally we could like to deal this
2512                  * problem the other way around (i.e.  if code == NOCPS
2513                  * ignore else retry next time) but the problem is that
2514                  * there're other errors (i.e.  EPERM) for which we don't
2515                  * want to retry and we don't know the whole code list!
2516                  */
2517                 if (code < 0 || code == UNOQUORUM || code == UNOTSYNC)
2518                     client->prfail = 1;
2519             }
2520         }
2521         /* the disabling of system:administrators is so iffy and has so many
2522          * possible failure modes that we will disable it again */
2523         /* Turn off System:Administrator for safety
2524          * if (AL_IsAMember(SystemId, client->CPS) == 0)
2525          * osi_Assert(AL_DisableGroup(SystemId, client->CPS) == 0); */
2526     }
2527
2528     /* Now, tcon may already be set to a rock, since we blocked with no host
2529      * or client locks set above in pr_GetCPS (XXXX some locking is probably
2530      * required).  So, before setting the RPC's rock, we should disconnect
2531      * the RPC from the other client structure's rock.
2532      */
2533     oldClient = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2534     if (oldClient && oldClient != client
2535         && oldClient->sid == rx_GetConnectionId(tcon)
2536         && oldClient->VenusEpoch == rx_GetConnectionEpoch(tcon)
2537         && !(oldClient->host->hostFlags & HOSTDELETED)) {
2538         char hoststr[16];
2539         if (!oldClient->deleted) {
2540             /* if we didn't create it, it's not ours to put back */
2541             if (created) {
2542                 ViceLog(0, ("FindClient: stillborn client %p(%x); "
2543                             "conn %p (host %s:%d) had client %p(%x)\n",
2544                             client, client->sid, tcon,
2545                             afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2546                             ntohs(rxr_PortOf(tcon)),
2547                             oldClient, oldClient->sid));
2548                 if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
2549                     free(client->CPS.prlist_val);
2550                 client->CPS.prlist_val = NULL;
2551                 client->CPS.prlist_len = 0;
2552             }
2553             /* We should perhaps check for 0 here */
2554             client->refCount--;
2555             ReleaseWriteLock(&client->lock);
2556             if (created) {
2557                 FreeCE(client);
2558                 created = 0;
2559             }
2560             oldClient->refCount++;
2561
2562             h_Hold_r(oldClient->host);
2563             h_Release_r(client->host);
2564
2565             H_UNLOCK;
2566             ObtainWriteLock(&oldClient->lock);
2567             H_LOCK;
2568             client = oldClient;
2569             host = oldClient->host;
2570         } else {
2571             ViceLog(0, ("FindClient: deleted client %p(%x ref %d host %p href "
2572                         "%d) already had conn %p (host %s:%d, cid %x), stolen "
2573                         "by client %p(%x, ref %d host %p href %d)\n",
2574                         oldClient, oldClient->sid, oldClient->refCount,
2575                         oldClient->host, oldClient->host->refCount, tcon,
2576                         afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2577                         ntohs(rxr_PortOf(tcon)), rx_GetConnectionId(tcon),
2578                         client, client->sid, client->refCount,
2579                         client->host, client->host->refCount));
2580             /* rx_SetSpecific will be done immediately below */
2581         }
2582     }
2583     /* Avoid chaining in more than once. */
2584     if (created) {
2585         h_Lock_r(host);
2586
2587         if (host->hostFlags & HOSTDELETED) {
2588             h_Unlock_r(host);
2589             h_Release_r(host);
2590
2591             host = NULL;
2592             client->host = NULL;
2593
2594             if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
2595                 free(client->CPS.prlist_val);
2596             client->CPS.prlist_val = NULL;
2597             client->CPS.prlist_len = 0;
2598
2599             client->refCount--;
2600             ReleaseWriteLock(&client->lock);
2601             FreeCE(client);
2602             return NULL;
2603         }
2604
2605         client->next = host->FirstClient;
2606         host->FirstClient = client;
2607         h_Unlock_r(host);
2608         CurrentConnections++;   /* increment number of connections */
2609     }
2610     rx_SetSpecific(tcon, rxcon_client_key, client);
2611     ReleaseWriteLock(&client->lock);
2612
2613     return client;
2614
2615 }                               /*h_FindClient_r */
2616
2617 int
2618 h_ReleaseClient_r(struct client *client)
2619 {
2620     osi_Assert(client->refCount > 0);
2621     client->refCount--;
2622     return 0;
2623 }
2624
2625
2626 /*
2627  * Sigh:  this one is used to get the client AGAIN within the individual
2628  * server routines.  This does not bother h_Holding the host, since
2629  * this is assumed already have been done by the server main loop.
2630  * It does check tokens, since only the server routines can return the
2631  * VICETOKENDEAD error code
2632  */
2633 int
2634 GetClient(struct rx_connection *tcon, struct client **cp)
2635 {
2636     struct client *client;
2637     char hoststr[16];
2638
2639     H_LOCK;
2640     *cp = NULL;
2641     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2642     if (client == NULL) {
2643         ViceLog(0,
2644                 ("GetClient: no client in conn %p (host %s:%d), VBUSYING\n",
2645                  tcon, afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2646                  ntohs(rxr_PortOf(tcon))));
2647         H_UNLOCK;
2648         return VBUSY;
2649     }
2650     if (rx_GetConnectionId(tcon) != client->sid
2651         || rx_GetConnectionEpoch(tcon) != client->VenusEpoch) {
2652         ViceLog(0,
2653                 ("GetClient: tcon %p tcon sid %d client sid %d\n",
2654                  tcon, rx_GetConnectionId(tcon), client->sid));
2655         H_UNLOCK;
2656         return VBUSY;
2657     }
2658     if (client && client->LastCall > client->expTime && client->expTime) {
2659         ViceLog(1,
2660                 ("Token for %s at %s:%d expired %d\n", h_UserName(client),
2661                  afs_inet_ntoa_r(client->host->host, hoststr),
2662                  ntohs(client->host->port), client->expTime));
2663         H_UNLOCK;
2664         return VICETOKENDEAD;
2665     }
2666     if (client->deleted) {
2667         ViceLog(0, ("GetClient: got deleted client, connection will appear "
2668                     "anonymous; tcon %p cid %x client %p ref %d host %p "
2669                     "(%s:%d) href %d ViceId %d\n",
2670                     tcon, rx_GetConnectionId(tcon), client, client->refCount,
2671                     client->host,
2672                     afs_inet_ntoa_r(client->host->host, hoststr),
2673                     (int)ntohs(client->host->port), client->host->refCount,
2674                     (int)client->ViceId));
2675     }
2676
2677     client->refCount++;
2678     *cp = client;
2679     H_UNLOCK;
2680     return 0;
2681 }                               /*GetClient */
2682
2683 int
2684 PutClient(struct client **cp)
2685 {
2686     if (*cp == NULL)
2687         return -1;
2688
2689     H_LOCK;
2690     h_ReleaseClient_r(*cp);
2691     *cp = NULL;
2692     H_UNLOCK;
2693     return 0;
2694 }                               /*PutClient */
2695
2696
2697 /* Client user name for short term use.  Note that this is NOT inexpensive */
2698 char *
2699 h_UserName(struct client *client)
2700 {
2701     static char User[PR_MAXNAMELEN + 1];
2702     namelist lnames;
2703     idlist lids;
2704
2705     lids.idlist_len = 1;
2706     lids.idlist_val = (afs_int32 *) malloc(1 * sizeof(afs_int32));
2707     if (!lids.idlist_val) {
2708         ViceLogThenPanic(0, ("Failed malloc in h_UserName\n"));
2709     }
2710     lnames.namelist_len = 0;
2711     lnames.namelist_val = (prname *) 0;
2712     lids.idlist_val[0] = client->ViceId;
2713     if (hpr_IdToName(&lids, &lnames)) {
2714         /* We need to free id we alloced above! */
2715         free(lids.idlist_val);
2716         return "*UNKNOWN USER NAME*";
2717     }
2718     strncpy(User, lnames.namelist_val[0], PR_MAXNAMELEN);
2719     free(lids.idlist_val);
2720     free(lnames.namelist_val);
2721     return User;
2722 }                               /*h_UserName */
2723
2724
2725 void
2726 h_PrintStats(void)
2727 {
2728     ViceLog(0,
2729             ("Total Client entries = %d, blocks = %d; Host entries = %d, blocks = %d\n",
2730              CEs, CEBlocks, HTs, HTBlocks));
2731
2732 }                               /*h_PrintStats */
2733
2734
2735 static int
2736 h_PrintClient(struct host *host, void *rock)
2737 {
2738     StreamHandle_t *file = (StreamHandle_t *)rock;
2739     struct client *client;
2740     int i;
2741     char tmpStr[256];
2742     char tbuffer[32];
2743     char hoststr[16];
2744     time_t LastCall, expTime;
2745     struct tm tm;
2746
2747     H_LOCK;
2748     LastCall = host->LastCall;
2749     if (host->hostFlags & HOSTDELETED) {
2750         H_UNLOCK;
2751         return 0;
2752     }
2753     strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y",
2754              localtime_r(&LastCall, &tm));
2755     snprintf(tmpStr, sizeof tmpStr, "Host %s:%d down = %d, LastCall %s\n",
2756              afs_inet_ntoa_r(host->host, hoststr),
2757              ntohs(host->port), (host->hostFlags & VENUSDOWN),
2758              tbuffer);
2759     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2760     for (client = host->FirstClient; client; client = client->next) {
2761         if (!client->deleted) {
2762             expTime = client->expTime;
2763             strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y",
2764                      localtime_r(&expTime, &tm));
2765             snprintf(tmpStr, sizeof tmpStr,
2766                      "    user id=%d,  name=%s, sl=%s till %s\n",
2767                      client->ViceId, h_UserName(client),
2768                      client->authClass ? "Authenticated"
2769                                        : "Not authenticated",
2770                      client->authClass ? tbuffer : "No Limit");
2771             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2772             snprintf(tmpStr, sizeof tmpStr, "      CPS-%d is [",
2773                          client->CPS.prlist_len);
2774             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2775             if (client->CPS.prlist_val) {
2776                 for (i = 0; i < client->CPS.prlist_len; i++) {
2777                     snprintf(tmpStr, sizeof tmpStr, " %d",
2778                              client->CPS.prlist_val[i]);
2779                     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2780                 }
2781             }
2782             sprintf(tmpStr, "]\n");
2783             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2784         }
2785     }
2786     H_UNLOCK;
2787     return 0;
2788
2789 }                               /*h_PrintClient */
2790
2791
2792
2793 /*
2794  * Print a list of clients, with last security level and token value seen,
2795  * if known
2796  */
2797 void
2798 h_PrintClients(void)
2799 {
2800     time_t now;
2801     char tmpStr[256];
2802     char tbuffer[32];
2803     struct tm tm;
2804
2805     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_CLNTDUMP_FILEPATH, "w");
2806
2807     if (file == NULL) {
2808         ViceLog(0,
2809                 ("Couldn't create client dump file %s\n",
2810                  AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2811         return;
2812     }
2813     now = FT_ApproxTime();
2814     strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y",
2815              localtime_r(&now, &tm));
2816     snprintf(tmpStr, sizeof tmpStr, "List of active users at %s\n\n",
2817              tbuffer);
2818     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2819     h_Enumerate(h_PrintClient, (char *)file);
2820     STREAM_REALLYCLOSE(file);
2821     ViceLog(0, ("Created client dump %s\n", AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2822 }
2823
2824
2825
2826
2827 static int
2828 h_DumpHost(struct host *host, void *rock)
2829 {
2830     StreamHandle_t *file = (StreamHandle_t *)rock;
2831
2832     int i;
2833     char tmpStr[256];
2834     char hoststr[16];
2835
2836     H_LOCK;
2837     snprintf(tmpStr, sizeof tmpStr,
2838              "ip:%s port:%d hidx:%d cbid:%d lock:%x last:%u active:%u "
2839              "down:%d del:%d cons:%d cldel:%d\n\t hpfailed:%d hcpsCall:%u "
2840              "hcps [",
2841              afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
2842              host->index, host->cblist, CheckLock(&host->lock),
2843              host->LastCall, host->ActiveCall, (host->hostFlags & VENUSDOWN),
2844              host->hostFlags & HOSTDELETED, host->Console,
2845              host->hostFlags & CLIENTDELETED, host->hcpsfailed,
2846              host->cpsCall);
2847     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2848     if (host->hcps.prlist_val)
2849         for (i = 0; i < host->hcps.prlist_len; i++) {
2850             snprintf(tmpStr, sizeof tmpStr, " %d", host->hcps.prlist_val[i]);
2851             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2852         }
2853     sprintf(tmpStr, "] [");
2854     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2855     if (host->interface)
2856         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
2857             char hoststr[16];
2858             sprintf(tmpStr, " %s:%d",
2859                      afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2860                      ntohs(host->interface->interface[i].port));
2861             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2862         }
2863     sprintf(tmpStr, "] refCount:%d hostFlags:%hu\n", host->refCount, host->hostFlags);
2864     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2865
2866     H_UNLOCK;
2867     return 0;
2868
2869 }                               /*h_DumpHost */
2870
2871
2872 void
2873 h_DumpHosts(void)
2874 {
2875     time_t now;
2876     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_HOSTDUMP_FILEPATH, "w");
2877     char tmpStr[256];
2878     char tbuffer[32];
2879     struct tm tm;
2880
2881     if (file == NULL) {
2882         ViceLog(0,
2883                 ("Couldn't create host dump file %s\n",
2884                  AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2885         return;
2886     }
2887     now = FT_ApproxTime();
2888     strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y",
2889              localtime_r(&now, &tm));
2890     snprintf(tmpStr, sizeof tmpStr, "List of active hosts at %s\n\n", tbuffer);
2891     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2892     h_Enumerate(h_DumpHost, (char *)file);
2893     STREAM_REALLYCLOSE(file);
2894     ViceLog(0, ("Created host dump %s\n", AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2895
2896 }                               /*h_DumpHosts */
2897
2898 #ifdef AFS_DEMAND_ATTACH_FS
2899 /*
2900  * demand attach fs
2901  * host state serialization
2902  */
2903 static int h_stateFillHeader(struct host_state_header * hdr);
2904 static int h_stateCheckHeader(struct host_state_header * hdr);
2905 static int h_stateAllocMap(struct fs_dump_state * state);
2906 static int h_stateSaveHost(struct host * host, void *rock);
2907 static int h_stateRestoreHost(struct fs_dump_state * state);
2908 static int h_stateRestoreIndex(struct host * h, void *rock);
2909 static int h_stateVerifyHost(struct host * h, void *rock);
2910 static int h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h,
2911                                  afs_uint32 addr, afs_uint16 port, int valid);
2912 static int h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h);
2913 static void h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out);
2914 static void h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out);
2915
2916 /**
2917  * Is this host busy?
2918  *
2919  * This is just a hint and should not be trusted; this should probably only be
2920  * used by the host state serialization code when trying to detect if a host
2921  * can be sanely serialized to disk or not. If this function returns 1, the
2922  * host may be in an invalid state and thus should not be saved to disk.
2923  */
2924 static int
2925 h_isBusy_r(struct host *host)
2926 {
2927     struct Lock *hostLock = &host->lock;
2928     int locked = 0;
2929
2930     LOCK_LOCK(hostLock);
2931     if (hostLock->excl_locked || hostLock->readers_reading) {
2932         locked = 1;
2933     }
2934     LOCK_UNLOCK(hostLock);
2935
2936     if (locked) {
2937         return 1;
2938     }
2939
2940     if ((host->hostFlags & HWHO_INPROGRESS) || !(host->hostFlags & ALTADDR)) {
2941         /* We shouldn't hit this if the host wasn't locked, but just in case... */
2942         return 1;
2943     }
2944
2945     return 0;
2946 }
2947
2948 /* this procedure saves all host state to disk for fast startup */
2949 int
2950 h_stateSave(struct fs_dump_state * state)
2951 {
2952     AssignInt64(state->eof_offset, &state->hdr->h_offset);
2953
2954     /* XXX debug */
2955     ViceLog(0, ("h_stateSave:  hostCount=%d\n", hostCount));
2956
2957     /* invalidate host state header */
2958     memset(state->h_hdr, 0, sizeof(struct host_state_header));
2959
2960     if (fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2961                             sizeof(struct host_state_header))) {
2962         state->bail = 1;
2963         goto done;
2964     }
2965
2966     fs_stateIncEOF(state, sizeof(struct host_state_header));
2967
2968     h_Enumerate_r(h_stateSaveHost, hostList, (char *)state);
2969     if (state->bail) {
2970         goto done;
2971     }
2972
2973     h_stateFillHeader(state->h_hdr);
2974
2975     /* write the real header to disk */
2976     state->bail = fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2977                                       sizeof(struct host_state_header));
2978
2979  done:
2980     return state->bail;
2981 }
2982
2983 /* demand attach fs
2984  * host state serialization
2985  *
2986  * this procedure restores all host state from a disk for fast startup
2987  */
2988 int
2989 h_stateRestore(struct fs_dump_state * state)
2990 {
2991     int i, records;
2992
2993     /* seek to the right position and read in the host state header */
2994     if (fs_stateReadHeader(state, &state->hdr->h_offset, state->h_hdr,
2995                            sizeof(struct host_state_header))) {
2996         state->bail = 1;
2997         goto done;
2998     }
2999
3000     /* check the validity of the header */
3001     if (h_stateCheckHeader(state->h_hdr)) {
3002         state->bail = 1;
3003         goto done;
3004     }
3005
3006     records = state->h_hdr->records;
3007
3008     if (h_stateAllocMap(state)) {
3009         state->bail = 1;
3010         goto done;
3011     }
3012
3013     /* iterate over records restoring host state */
3014     for (i=0; i < records; i++) {
3015         if (h_stateRestoreHost(state) != 0) {
3016             state->bail = 1;
3017             break;
3018         }
3019     }
3020
3021  done:
3022     return state->bail;
3023 }
3024
3025 int
3026 h_stateRestoreIndices(struct fs_dump_state * state)
3027 {
3028     h_Enumerate_r(h_stateRestoreIndex, hostList, (char *)state);
3029     return state->bail;
3030 }
3031
3032 static int
3033 h_stateRestoreIndex(struct host * h, void *rock)
3034 {
3035     struct fs_dump_state *state = (struct fs_dump_state *)rock;
3036     if (cb_OldToNew(state, h->cblist, &h->cblist)) {
3037         return H_ENUMERATE_BAIL(0);
3038     }
3039     return 0;
3040 }
3041
3042 int
3043 h_stateVerify(struct fs_dump_state * state)
3044 {
3045     h_Enumerate_r(h_stateVerifyHost, hostList, (char *)state);
3046     return state->bail;
3047 }
3048
3049 static int
3050 h_stateVerifyHost(struct host * h, void* rock)
3051 {
3052     struct fs_dump_state *state = (struct fs_dump_state *)rock;
3053     int i;
3054
3055     if (h == NULL) {
3056         ViceLog(0, ("h_stateVerifyHost: error: NULL host pointer in linked list\n"));
3057         return H_ENUMERATE_BAIL(0);
3058     }
3059
3060     if (h->interface) {
3061         for (i = h->interface->numberOfInterfaces-1; i >= 0; i--) {
3062             if (h_stateVerifyAddrHash(state, h, h->interface->interface[i].addr,
3063                                       h->interface->interface[i].port,
3064                                       h->interface->interface[i].valid)) {
3065                 state->bail = 1;
3066             }
3067         }
3068         if (h_stateVerifyUuidHash(state, h)) {
3069             state->bail = 1;
3070         }
3071     } else if (h_stateVerifyAddrHash(state, h, h->host, h->port, 1)) {
3072         state->bail = 1;
3073     }
3074
3075     if (cb_stateVerifyHCBList(state, h)) {
3076         state->bail = 1;
3077     }
3078
3079     return 0;
3080 }
3081
3082 /**
3083  * verify a host is either in, or absent from, the addr hash table.
3084  *
3085  * @param[in] state  fs dump state
3086  * @param[in] h      host we're dealing with
3087  * @param[in] addr   addr to look for (NBO)
3088  * @param[in] port   port to look for (NBO)
3089  * @param[in] valid  1 if we're verifying that the specified addr and port
3090  *                   in the hash table point to the specified host. 0 if we're
3091  *                   verifying that the specified addr and port do NOT point
3092  *                   to the specified host
3093  *
3094  * @return operation status
3095  *  @retval 1 failed to verify, bail out
3096  *  @retval 0 verified successfully, all is well
3097  */
3098 static int
3099 h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h,
3100                       afs_uint32 addr, afs_uint16 port, int valid)
3101 {
3102     int ret = 0, found = 0;
3103     struct host *host = NULL;
3104     struct h_AddrHashChain *chain;
3105     int index = h_HashIndex(addr);
3106     char tmp[16];
3107     int chain_len = 0;
3108
3109     for (chain = hostAddrHashTable[index]; chain; chain = chain->next) {
3110         host = chain->hostPtr;
3111         if (host == NULL) {
3112             afs_inet_ntoa_r(addr, tmp);
3113             ViceLog(0, ("h_stateVerifyAddrHash: error: addr hash chain has NULL host ptr (lookup addr %s)\n", tmp));
3114             ret = 1;
3115             goto done;
3116         }
3117         if ((chain->addr == addr) && (chain->port == port)) {
3118             if (host != h) {
3119                 if (valid) {
3120                     ViceLog(0, ("h_stateVerifyAddrHash: warning: addr hash entry "
3121                                 "points to different host struct (%d, %d)\n",
3122                                 h->index, host->index));
3123                     state->flags.warnings_generated = 1;
3124                 }
3125             } else {
3126                 if (!valid) {
3127                     ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s:%u is "
3128                                 "marked invalid, but points to the containing "
3129                                 "host\n", afs_inet_ntoa_r(addr, tmp),
3130                                 (unsigned)htons(port)));
3131                     ret = 1;
3132                     goto done;
3133                 }
3134             }
3135             found = 1;
3136             break;
3137         }
3138         if (chain_len > FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN) {
3139             ViceLog(0, ("h_stateVerifyAddrHash: error: hash chain length exceeds %d; assuming there's a loop\n",
3140                         FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN));
3141             ret = 1;
3142             goto done;
3143         }
3144         chain_len++;
3145     }
3146
3147     if (!found && valid) {
3148         afs_inet_ntoa_r(addr, tmp);
3149         if (state->mode == FS_STATE_LOAD_MODE) {
3150             ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s:%u not found in hash\n",
3151                         tmp, (unsigned)htons(port)));
3152             ret = 1;
3153             goto done;
3154         } else {
3155             ViceLog(0, ("h_stateVerifyAddrHash: warning: addr %s:%u not found in hash\n",
3156                         tmp, (unsigned)htons(port)));
3157             state->flags.warnings_generated = 1;
3158         }
3159     }
3160
3161  done:
3162     return ret;
3163 }
3164
3165 static int
3166 h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h)
3167 {
3168     int ret = 0, found = 0;
3169     struct host *host = NULL;
3170     struct h_UuidHashChain *chain;
3171     afsUUID * uuidp = &h->interface->uuid;
3172     int index = h_UuidHashIndex(uuidp);
3173     char tmp[40];
3174     int chain_len = 0;
3175
3176     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
3177         host = chain->hostPtr;
3178         if (host == NULL) {
3179             afsUUID_to_string(uuidp, tmp, sizeof(tmp));
3180             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid hash chain has NULL host ptr (lookup uuid %s)\n", tmp));
3181             ret = 1;
3182             goto done;
3183         }
3184         if (host->interface &&
3185             afs_uuid_equal(&host->interface->uuid, uuidp)) {
3186             if (host != h) {
3187                 ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid hash entry points to different host struct (%d, %d)\n",
3188                             h->index, host->index));
3189                 state->flags.warnings_generated = 1;
3190             }
3191             found = 1;
3192             goto done;
3193         }
3194         if (chain_len > FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN) {
3195             ViceLog(0, ("h_stateVerifyUuidHash: error: hash chain length exceeds %d; assuming there's a loop\n",
3196                         FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN));
3197             ret = 1;
3198             goto done;
3199         }
3200         chain_len++;
3201     }
3202
3203     if (!found) {
3204         afsUUID_to_string(uuidp, tmp, sizeof(tmp));
3205         if (state->mode == FS_STATE_LOAD_MODE) {
3206             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid %s not found in hash\n", tmp));
3207             ret = 1;
3208             goto done;
3209         } else {
3210             ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid %s not found in hash\n", tmp));
3211             state->flags.warnings_generated = 1;
3212         }
3213     }
3214
3215  done:
3216     return ret;
3217 }
3218
3219 /* create the host state header structure */
3220 static int
3221 h_stateFillHeader(struct host_state_header * hdr)
3222 {
3223     hdr->stamp.magic = HOST_STATE_MAGIC;
3224     hdr->stamp.version = HOST_STATE_VERSION;
3225     return 0;
3226 }
3227
3228 /* check the contents of the host state header structure */
3229 static int
3230 h_stateCheckHeader(struct host_state_header * hdr)
3231 {
3232     int ret=0;
3233
3234     if (hdr->stamp.magic != HOST_STATE_MAGIC) {
3235         ViceLog(0, ("check_host_state_header: invalid state header\n"));
3236         ret = 1;
3237     }
3238     else if (hdr->stamp.version != HOST_STATE_VERSION) {
3239         ViceLog(0, ("check_host_state_header: unknown version number\n"));
3240         ret = 1;
3241     }
3242     return ret;
3243 }
3244
3245 /* allocate the host id mapping table */
3246 static int
3247 h_stateAllocMap(struct fs_dump_state * state)
3248 {
3249     state->h_map.len = state->h_hdr->index_max + 1;
3250     state->h_map.entries = (struct idx_map_entry_t *)
3251         calloc(state->h_map.len, sizeof(struct idx_map_entry_t));
3252     return (state->h_map.entries != NULL) ? 0 : 1;
3253 }
3254
3255 /* function called by h_Enumerate to save a host to disk */
3256 static int
3257 h_stateSaveHost(struct host * host, void* rock)
3258 {
3259     struct fs_dump_state *state = (struct fs_dump_state *) rock;
3260     int if_len=0, hcps_len=0;
3261     struct hostDiskEntry hdsk;
3262     struct host_state_entry_header hdr;
3263     struct Interface * ifp = NULL;
3264     afs_int32 * hcps = NULL;
3265     struct iovec iov[4];
3266     int iovcnt = 2;
3267
3268     if (h_isBusy_r(host)) {
3269         char hoststr[16];
3270         ViceLog(1, ("Not saving host %s:%d to disk; host appears busy\n",
3271                     afs_inet_ntoa_r(host->host, hoststr), (int)ntohs(host->port)));
3272         /* Make sure we don't try to save callbacks to disk for this host, or
3273          * we'll get confused on restore */
3274         DeleteAllCallBacks_r(host, 1);
3275         return 0;
3276     }
3277
3278     memset(&hdr, 0, sizeof(hdr));
3279
3280     if (state->h_hdr->index_max < host->index) {
3281         state->h_hdr->index_max = host->index;
3282     }
3283
3284     h_hostToDiskEntry_r(host, &hdsk);
3285     if (host->interface) {
3286         if_len = sizeof(struct Interface) +
3287             ((host->interface->numberOfInterfaces-1) * sizeof(struct AddrPort));
3288         ifp = (struct Interface *) malloc(if_len);
3289         osi_Assert(ifp != NULL);
3290         memcpy(ifp, host->interface, if_len);
3291         hdr.interfaces = host->interface->numberOfInterfaces;
3292         iov[iovcnt].iov_base = (char *) ifp;
3293         iov[iovcnt].iov_len = if_len;
3294         iovcnt++;
3295     }
3296     if (host->hcps.prlist_val) {
3297         hdr.hcps = host->hcps.prlist_len;
3298         hcps_len = hdr.hcps * sizeof(afs_int32);
3299         hcps = (afs_int32 *) malloc(hcps_len);
3300         osi_Assert(hcps != NULL);
3301         memcpy(hcps, host->hcps.prlist_val, hcps_len);
3302         iov[iovcnt].iov_base = (char *) hcps;
3303         iov[iovcnt].iov_len = hcps_len;
3304         iovcnt++;
3305     }
3306
3307     if (hdsk.index > state->h_hdr->index_max)
3308         state->h_hdr->index_max = hdsk.index;
3309
3310     hdr.len = sizeof(struct host_state_entry_header) +
3311         sizeof(struct hostDiskEntry) + if_len + hcps_len;
3312     hdr.magic = HOST_STATE_ENTRY_MAGIC;
3313
3314     iov[0].iov_base = (char *) &hdr;
3315     iov[0].iov_len = sizeof(hdr);
3316     iov[1].iov_base = (char *) &hdsk;
3317     iov[1].iov_len = sizeof(struct hostDiskEntry);
3318
3319     if (fs_stateWriteV(state, iov, iovcnt)) {
3320         ViceLog(0, ("h_stateSaveHost: failed to save host %d", host->index));
3321         state->bail = 1;
3322     }
3323
3324     fs_stateIncEOF(state, hdr.len);
3325
3326     state->h_hdr->records++;
3327
3328     if (ifp)
3329         free(ifp);
3330     if (hcps)
3331         free(hcps);
3332     if (state->bail) {
3333         return H_ENUMERATE_BAIL(0);
3334     }
3335     return 0;
3336 }
3337
3338 /* restores a host from disk */
3339 static int
3340 h_stateRestoreHost(struct fs_dump_state * state)
3341 {
3342     int ifp_len=0, hcps_len=0, bail=0;
3343     struct host_state_entry_header hdr;
3344     struct hostDiskEntry hdsk;
3345     struct host *host = NULL;
3346     struct Interface *ifp = NULL;
3347     afs_int32 * hcps = NULL;
3348     struct iovec iov[3];
3349     int iovcnt = 1;
3350
3351     if (fs_stateRead(state, &hdr, sizeof(hdr))) {
3352         ViceLog(0, ("h_stateRestoreHost: failed to read host entry header from dump file '%s'\n",
3353                     state->fn));
3354         bail = 1;
3355         goto done;
3356     }
3357
3358     if (hdr.magic != HOST_STATE_ENTRY_MAGIC) {
3359         ViceLog(0, ("h_stateRestoreHost: fileserver state dump file '%s' is corrupt.\n",
3360                     state->fn));
3361         bail = 1;
3362         goto done;
3363     }
3364
3365     iov[0].iov_base = (char *) &hdsk;
3366     iov[0].iov_len = sizeof(struct hostDiskEntry);
3367
3368     if (hdr.interfaces) {
3369         ifp_len = sizeof(struct Interface) +
3370             ((hdr.interfaces-1) * sizeof(struct AddrPort));
3371         ifp = (struct Interface *) malloc(ifp_len);
3372         osi_Assert(ifp != NULL);
3373         iov[iovcnt].iov_base = (char *) ifp;
3374         iov[iovcnt].iov_len = ifp_len;
3375         iovcnt++;
3376     }
3377     if (hdr.hcps) {
3378         hcps_len = hdr.hcps * sizeof(afs_int32);
3379         hcps = (afs_int32 *) malloc(hcps_len);
3380         osi_Assert(hcps != NULL);
3381         iov[iovcnt].iov_base = (char *) hcps;
3382         iov[iovcnt].iov_len = hcps_len;
3383         iovcnt++;
3384     }
3385
3386     if ((ifp_len + hcps_len + sizeof(hdsk) + sizeof(hdr)) != hdr.len) {
3387         ViceLog(0, ("h_stateRestoreHost: host entry header length fields are inconsistent\n"));
3388         bail = 1;
3389         goto done;
3390     }
3391
3392     if (fs_stateReadV(state, iov, iovcnt)) {
3393         ViceLog(0, ("h_stateRestoreHost: failed to read host entry\n"));
3394         bail = 1;
3395         goto done;
3396     }
3397
3398     if (!hdr.hcps && hdsk.hcps_valid) {
3399         /* valid, zero-length host cps ; does this ever happen? */
3400         hcps = (afs_int32 *) malloc(sizeof(afs_int32));
3401         osi_Assert(hcps != NULL);
3402     }
3403
3404     if ((hdsk.hostFlags & HWHO_INPROGRESS) || !(hdsk.hostFlags & ALTADDR)) {
3405         char hoststr[16];
3406         ViceLog(0, ("h_stateRestoreHost: skipping host %s:%d due to invalid flags 0x%x\n",
3407                     afs_inet_ntoa_r(hdsk.host, hoststr), (int)ntohs(hdsk.port),
3408                     (unsigned)hdsk.hostFlags));
3409         bail = 0;
3410         state->h_map.entries[hdsk.index].valid = FS_STATE_IDX_SKIPPED;
3411         goto done;
3412     }
3413
3414     /* for restoring state, we better be able to get a host! */
3415     host = GetHT();
3416     osi_Assert(host != NULL);
3417
3418     if (ifp) {
3419         host->interface = ifp;
3420     }
3421     if (hcps) {
3422         host->hcps.prlist_val = hcps;
3423         host->hcps.prlist_len = hdr.hcps;
3424     }
3425
3426     h_diskEntryToHost_r(&hdsk, host);
3427     h_SetupCallbackConn_r(host);
3428
3429     h_AddHostToAddrHashTable_r(host->host, host->port, host);
3430     if (ifp) {
3431         int i;
3432         for (i = ifp->numberOfInterfaces-1; i >= 0; i--) {
3433             if (ifp->interface[i].valid &&
3434                 !(ifp->interface[i].addr == host->host &&
3435                   ifp->interface[i].port == host->port)) {
3436                 h_AddHostToAddrHashTable_r(ifp->interface[i].addr,
3437                                            ifp->interface[i].port,
3438                                            host);
3439             }
3440         }
3441         h_AddHostToUuidHashTable_r(&ifp->uuid, host);
3442     }
3443     h_InsertList_r(host);
3444
3445     /* setup host id map entry */
3446     state->h_map.entries[hdsk.index].valid = FS_STATE_IDX_VALID;
3447     state->h_map.entries[hdsk.index].old_idx = hdsk.index;
3448     state->h_map.entries[hdsk.index].new_idx = host->index;
3449
3450  done:
3451     if (bail) {
3452         if (ifp)
3453             free(ifp);
3454         if (hcps)
3455             free(hcps);
3456     }
3457     return bail;
3458 }
3459
3460 /* serialize a host structure to disk */
3461 static void
3462 h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out)
3463 {
3464     out->host = in->host;
3465     out->port = in->port;
3466     out->hostFlags = in->hostFlags;
3467     out->Console = in->Console;
3468     out->hcpsfailed = in->hcpsfailed;
3469     out->LastCall = in->LastCall;
3470     out->ActiveCall = in->ActiveCall;
3471     out->cpsCall = in->cpsCall;
3472     out->cblist = in->cblist;
3473     out->InSameNetwork = in->InSameNetwork;
3474
3475     /* special fields we save, but are not memcpy'd back on restore */
3476     out->index = in->index;
3477     out->hcps_len = in->hcps.prlist_len;
3478     out->hcps_valid = (in->hcps.prlist_val == NULL) ? 0 : 1;
3479 }
3480
3481 /* restore a host structure from disk */
3482 static void
3483 h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out)
3484 {
3485     out->host = in->host;
3486     out->port = in->port;
3487     out->hostFlags = in->hostFlags;
3488     out->Console = in->Console;
3489     out->hcpsfailed = in->hcpsfailed;
3490     out->LastCall = in->LastCall;
3491     out->ActiveCall = in->ActiveCall;
3492     out->cpsCall = in->cpsCall;
3493     out->cblist = in->cblist;
3494     out->InSameNetwork = in->InSameNetwork;
3495 }
3496
3497 /* index translation routines */
3498 int
3499 h_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
3500 {
3501     int ret = 0;
3502
3503     /* hosts use a zero-based index, so old==0 is valid */
3504
3505     if (old >= state->h_map.len) {
3506         ViceLog(0, ("h_OldToNew: index %d is out of range\n", old));
3507         ret = 1;
3508     } else if (state->h_map.entries[old].valid != FS_STATE_IDX_VALID ||
3509                state->h_map.entries[old].old_idx != old) { /* sanity check */
3510         ViceLog(0, ("h_OldToNew: index %d points to an invalid host record\n", old));
3511         ret = 1;
3512     } else {
3513         *new = state->h_map.entries[old].new_idx;
3514     }
3515
3516     return ret;
3517 }
3518 #endif /* AFS_DEMAND_ATTACH_FS */
3519
3520
3521 /*
3522  * This counts the number of workstations, the number of active workstations,
3523  * and the number of workstations declared "down" (i.e. not heard from
3524  * recently).  An active workstation has received a call since the cutoff
3525  * time argument passed.
3526  */
3527 void
3528 h_GetWorkStats(int *nump, int *activep, int *delp, afs_int32 cutofftime)
3529 {
3530     struct host *host;
3531     int num = 0, active = 0, del = 0;
3532     int count;
3533
3534     H_LOCK;
3535     for (count = 0, host = hostList; host && count < hostCount; host = host->next, count++) {
3536         if (!(host->hostFlags & HOSTDELETED)) {
3537             num++;
3538             if (host->ActiveCall > cutofftime)
3539                 active++;
3540             if (host->hostFlags & VENUSDOWN)
3541                 del++;
3542         }
3543     }
3544     if (count != hostCount) {
3545         ViceLog(0, ("h_GetWorkStats found %d of %d hosts\n", count, hostCount));
3546     } else if (host != NULL) {
3547         ViceLog(0, ("h_GetWorkStats found more than %d hosts\n", hostCount));
3548         ShutDownAndCore(PANIC);
3549     }
3550     H_UNLOCK;
3551     if (nump)
3552         *nump = num;
3553     if (activep)
3554         *activep = active;
3555     if (delp)
3556         *delp = del;
3557
3558 }                               /*h_GetWorkStats */
3559
3560 void
3561 h_GetWorkStats64(afs_uint64 *nump, afs_uint64 *activep, afs_uint64 *delp, 
3562                  afs_int32 cutofftime)
3563 {
3564     int num, active, del;
3565     h_GetWorkStats(&num, &active, &del, cutofftime);
3566     if (nump)
3567         *nump = num;
3568     if (activep)
3569         *activep = active;
3570     if (delp)
3571         *delp = del;
3572 }
3573
3574 /*------------------------------------------------------------------------
3575  * PRIVATE h_ClassifyAddress
3576  *
3577  * Description:
3578  *      Given a target IP address and a candidate IP address (both
3579  *      in host byte order), classify the candidate into one of three
3580  *      buckets in relation to the target by bumping the counters passed
3581  *      in as parameters.
3582  *
3583  * Arguments:
3584  *      a_targetAddr       : Target address.
3585  *      a_candAddr         : Candidate address.
3586  *      a_sameNetOrSubnetP : Ptr to counter to bump when the two
3587  *                           addresses are either in the same network
3588  *                           or the same subnet.
3589  *      a_diffSubnetP      : ...when the candidate is in a different
3590  *                           subnet.
3591  *      a_diffNetworkP     : ...when the candidate is in a different
3592  *                           network.
3593  *
3594  * Returns:
3595  *      Nothing.
3596  *
3597  * Environment:
3598  *      The target and candidate addresses are both in host byte
3599  *      order, NOT network byte order, when passed in.
3600  *
3601  * Side Effects:
3602  *      As advertised.
3603  *------------------------------------------------------------------------*/
3604
3605 static void
3606 h_ClassifyAddress(afs_uint32 a_targetAddr, afs_uint32 a_candAddr,
3607                   afs_int32 * a_sameNetOrSubnetP, afs_int32 * a_diffSubnetP,
3608                   afs_int32 * a_diffNetworkP)
3609 {                               /*h_ClassifyAddress */
3610
3611     afs_uint32 targetNet;
3612     afs_uint32 targetSubnet;
3613     afs_uint32 candNet;
3614     afs_uint32 candSubnet;
3615
3616     /*
3617      * Put bad values into the subnet info to start with.
3618      */
3619     targetSubnet = (afs_uint32) 0;
3620     candSubnet = (afs_uint32) 0;
3621
3622     /*
3623      * Pull out the network and subnetwork numbers from the target
3624      * and candidate addresses.  We can short-circuit this whole
3625      * affair if the target and candidate addresses are not of the
3626      * same class.
3627      */
3628     if (IN_CLASSA(a_targetAddr)) {
3629         if (!(IN_CLASSA(a_candAddr))) {
3630             (*a_diffNetworkP)++;
3631             return;
3632         }
3633         targetNet = a_targetAddr & IN_CLASSA_NET;
3634         candNet = a_candAddr & IN_CLASSA_NET;
3635         if (IN_SUBNETA(a_targetAddr))
3636             targetSubnet = a_targetAddr & IN_CLASSA_SUBNET;
3637         if (IN_SUBNETA(a_candAddr))
3638             candSubnet = a_candAddr & IN_CLASSA_SUBNET;
3639     } else if (IN_CLASSB(a_targetAddr)) {
3640         if (!(IN_CLASSB(a_candAddr))) {
3641             (*a_diffNetworkP)++;
3642             return;
3643         }
3644         targetNet = a_targetAddr & IN_CLASSB_NET;
3645         candNet = a_candAddr & IN_CLASSB_NET;
3646         if (IN_SUBNETB(a_targetAddr))
3647             targetSubnet = a_targetAddr & IN_CLASSB_SUBNET;
3648         if (IN_SUBNETB(a_candAddr))
3649             candSubnet = a_candAddr & IN_CLASSB_SUBNET;
3650     } /*Class B target */
3651     else if (IN_CLASSC(a_targetAddr)) {
3652         if (!(IN_CLASSC(a_candAddr))) {
3653             (*a_diffNetworkP)++;
3654             return;
3655         }
3656         targetNet = a_targetAddr & IN_CLASSC_NET;
3657         candNet = a_candAddr & IN_CLASSC_NET;
3658
3659         /*
3660          * Note that class C addresses can't have subnets,
3661          * so we leave the defaults untouched.
3662          */
3663     } /*Class C target */
3664     else {
3665         targetNet = a_targetAddr;
3666         candNet = a_candAddr;
3667     }                           /*Class D address */
3668
3669     /*
3670      * Now, simply compare the extracted net and subnet values for
3671      * the two addresses (which at this point are known to be of the
3672      * same class)
3673      */
3674     if (targetNet == candNet) {
3675         if (targetSubnet == candSubnet)
3676             (*a_sameNetOrSubnetP)++;
3677         else
3678             (*a_diffSubnetP)++;
3679     } else
3680         (*a_diffNetworkP)++;
3681
3682 }                               /*h_ClassifyAddress */
3683
3684
3685 /*------------------------------------------------------------------------
3686  * EXPORTED h_GetHostNetStats
3687  *
3688  * Description:
3689  *      Iterate through the host table, and classify each (non-deleted)
3690  *      host entry into ``proximity'' categories (same net or subnet,
3691  *      different subnet, different network).
3692  *
3693  * Arguments:
3694  *      a_numHostsP        : Set to total number of (non-deleted) hosts.
3695  *      a_sameNetOrSubnetP : Set to # hosts on same net/subnet as server.
3696  *      a_diffSubnetP      : Set to # hosts on diff subnet as server.
3697  *      a_diffNetworkP     : Set to # hosts on diff network as server.
3698  *
3699  * Returns:
3700  *      Nothing.
3701  *
3702  * Environment:
3703  *      We only count non-deleted hosts.  The storage pointed to by our
3704  *      parameters is zeroed upon entry.
3705  *
3706  * Side Effects:
3707  *      As advertised.
3708  *------------------------------------------------------------------------*/
3709
3710 void
3711 h_GetHostNetStats(afs_int32 * a_numHostsP, afs_int32 * a_sameNetOrSubnetP,
3712                   afs_int32 * a_diffSubnetP, afs_int32 * a_diffNetworkP)
3713 {                               /*h_GetHostNetStats */
3714
3715     struct host *hostP; /*Ptr to current host entry */
3716     afs_uint32 currAddr_HBO;    /*Curr host addr, host byte order */
3717     int count;
3718
3719     /*
3720      * Clear out the storage pointed to by our parameters.
3721      */
3722     *a_numHostsP = (afs_int32) 0;
3723     *a_sameNetOrSubnetP = (afs_int32) 0;
3724     *a_diffSubnetP = (afs_int32) 0;
3725     *a_diffNetworkP = (afs_int32) 0;
3726
3727     H_LOCK;
3728     for (count = 0, hostP = hostList; hostP && count < hostCount; hostP = hostP->next, count++) {
3729         if (!(hostP->hostFlags & HOSTDELETED)) {
3730             /*
3731              * Bump the number of undeleted host entries found.
3732              * In classifying the current entry's address, make
3733              * sure to first convert to host byte order.
3734              */
3735             (*a_numHostsP)++;
3736             currAddr_HBO = (afs_uint32) ntohl(hostP->host);
3737             h_ClassifyAddress(FS_HostAddr_HBO, currAddr_HBO,
3738                               a_sameNetOrSubnetP, a_diffSubnetP,
3739                               a_diffNetworkP);
3740         }                       /*Only look at non-deleted hosts */
3741     }                           /*For each host record hashed to this index */
3742     if (count != hostCount) {
3743         ViceLog(0, ("h_GetHostNetStats found %d of %d hosts\n", count, hostCount));
3744     } else if (hostP != NULL) {
3745         ViceLog(0, ("h_GetHostNetStats found more than %d hosts\n", hostCount));
3746         ShutDownAndCore(PANIC);
3747     }
3748     H_UNLOCK;
3749 }                               /*h_GetHostNetStats */
3750
3751 static afs_uint32 checktime;
3752 static afs_uint32 clientdeletetime;
3753 static struct AFSFid zerofid;
3754
3755
3756 /*
3757  * XXXX: This routine could use Multi-Rx to avoid serializing the timeouts.
3758  * Since it can serialize them, and pile up, it should be a separate LWP
3759  * from other events.
3760  */
3761 #if 0
3762 static int
3763 CheckHost(struct host *host, int flags, void *rock)
3764 {
3765     struct client *client;
3766     struct rx_connection *cb_conn = NULL;
3767     int code;
3768
3769 #ifdef AFS_DEMAND_ATTACH_FS
3770     /* kill the checkhost lwp ASAP during shutdown */
3771     FS_STATE_RDLOCK;
3772     if (fs_state.mode == FS_MODE_SHUTDOWN) {
3773         FS_STATE_UNLOCK;
3774         return H_ENUMERATE_BAIL(flags);
3775     }
3776     FS_STATE_UNLOCK;
3777 #endif
3778
3779     /* Host is held by h_Enumerate */
3780     H_LOCK;
3781     for (client = host->FirstClient; client; client = client->next) {
3782         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
3783             client->deleted = 1;
3784             host->hostFlags |= CLIENTDELETED;
3785         }
3786     }
3787     if (host->LastCall < checktime) {
3788         h_Lock_r(host);
3789         if (!(host->hostFlags & HOSTDELETED)) {
3790             host->hostFlags |= HWHO_INPROGRESS;
3791             cb_conn = host->callback_rxcon;
3792             rx_GetConnection(cb_conn);
3793             if (host->LastCall < clientdeletetime) {
3794                 host->hostFlags |= HOSTDELETED;
3795                 if (!(host->hostFlags & VENUSDOWN)) {
3796                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
3797                     if (host->interface) {
3798                         H_UNLOCK;
3799                         code =
3800                             RXAFSCB_InitCallBackState3(cb_conn,
3801                                                        &FS_HostUUID);
3802                         H_LOCK;
3803                     } else {
3804                         H_UNLOCK;
3805                         code =
3806                             RXAFSCB_InitCallBackState(cb_conn);
3807                         H_LOCK;
3808                     }
3809                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
3810                     if (code) {
3811                         char hoststr[16];
3812                         (void)afs_inet_ntoa_r(host->host, hoststr);
3813                         ViceLog(0,
3814                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
3815                                  hoststr, ntohs(host->port)));
3816                         host->hostFlags |= VENUSDOWN;
3817                     }
3818                     /* Note:  it's safe to delete hosts even if they have call
3819                      * back state, because break delayed callbacks (called when a
3820                      * message is received from the workstation) will always send a
3821                      * break all call backs to the workstation if there is no
3822                      * callback.
3823                      */
3824                 }
3825             } else {
3826                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
3827                     char hoststr[16];
3828                     (void)afs_inet_ntoa_r(host->host, hoststr);
3829                     if (host->interface) {
3830                         afsUUID uuid = host->interface->uuid;
3831                         H_UNLOCK;
3832                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
3833                         H_LOCK;
3834                         if (code) {
3835                             if (MultiProbeAlternateAddress_r(host)) {
3836                                 ViceLog(0,("CheckHost: Probing all interfaces of host %s:%d failed, code %d\n",
3837                                             hoststr, ntohs(host->port), code));
3838                                 host->hostFlags |= VENUSDOWN;
3839                             }
3840                         }
3841                     } else {
3842                         H_UNLOCK;
3843                         code = RXAFSCB_Probe(cb_conn);
3844                         H_LOCK;
3845                         if (code) {
3846                             ViceLog(0,
3847                                     ("CheckHost: Probe failed for host %s:%d, code %d\n",
3848                                      hoststr, ntohs(host->port), code));
3849                             host->hostFlags |= VENUSDOWN;
3850                         }
3851                     }
3852                 }
3853             }
3854             H_UNLOCK;
3855             rx_PutConnection(cb_conn);
3856             cb_conn=NULL;
3857             H_LOCK;
3858             host->hostFlags &= ~HWHO_INPROGRESS;
3859         }
3860         h_Unlock_r(host);
3861     }
3862     H_UNLOCK;
3863     return held;
3864
3865 }                               /*CheckHost */
3866 #endif
3867
3868 int
3869 CheckHost_r(struct host *host, void *dummy)
3870 {
3871     struct client *client;
3872     struct rx_connection *cb_conn = NULL;
3873     int code;
3874
3875 #ifdef AFS_DEMAND_ATTACH_FS
3876     /* kill the checkhost lwp ASAP during shutdown */
3877     FS_STATE_RDLOCK;
3878     if (fs_state.mode == FS_MODE_SHUTDOWN) {
3879         FS_STATE_UNLOCK;
3880         return H_ENUMERATE_BAIL(0);
3881     }
3882     FS_STATE_UNLOCK;
3883 #endif
3884
3885     /* Host is held by h_Enumerate_r */
3886     for (client = host->FirstClient; client; client = client->next) {
3887         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
3888             client->deleted = 1;
3889             host->hostFlags |= CLIENTDELETED;
3890         }
3891     }
3892     if (host->LastCall < checktime) {
3893         h_Lock_r(host);
3894         if (!(host->hostFlags & HOSTDELETED)) {
3895             host->hostFlags |= HWHO_INPROGRESS;
3896             cb_conn = host->callback_rxcon;
3897             rx_GetConnection(cb_conn);
3898             if (host->LastCall < clientdeletetime) {
3899                 host->hostFlags |= HOSTDELETED;
3900                 if (!(host->hostFlags & VENUSDOWN)) {
3901                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
3902                     if (host->interface) {
3903                         H_UNLOCK;
3904                         code =
3905                             RXAFSCB_InitCallBackState3(cb_conn,
3906                                                        &FS_HostUUID);
3907                         H_LOCK;
3908                     } else {
3909                         H_UNLOCK;
3910                         code =
3911                             RXAFSCB_InitCallBackState(cb_conn);
3912                         H_LOCK;
3913                     }
3914                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
3915                     if (code) {
3916                         char hoststr[16];
3917                         (void)afs_inet_ntoa_r(host->host, hoststr);
3918                         ViceLog(0,
3919                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
3920                                  hoststr, ntohs(host->port)));
3921                         host->hostFlags |= VENUSDOWN;
3922                     }
3923                     /* Note:  it's safe to delete hosts even if they have call
3924                      * back state, because break delayed callbacks (called when a
3925                      * message is received from the workstation) will always send a
3926                      * break all call backs to the workstation if there is no
3927                      * callback.
3928                      */
3929                 }
3930             } else {
3931                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
3932                     char hoststr[16];
3933                     (void)afs_inet_ntoa_r(host->host, hoststr);
3934                     if (host->interface) {
3935                         afsUUID uuid = host->interface->uuid;
3936                         H_UNLOCK;
3937                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
3938                         H_LOCK;
3939                         if (code) {
3940                             if (MultiProbeAlternateAddress_r(host)) {
3941                                 ViceLog(0,("CheckHost_r: Probing all interfaces of host %s:%d failed, code %d\n",
3942                                             hoststr, ntohs(host->port), code));
3943                                 host->hostFlags |= VENUSDOWN;
3944                             }
3945                         }
3946                     } else {
3947                         H_UNLOCK;
3948                         code = RXAFSCB_Probe(cb_conn);
3949                         H_LOCK;
3950                         if (code) {
3951                             ViceLog(0,
3952                                     ("CheckHost_r: Probe failed for host %s:%d, code %d\n",
3953                                      hoststr, ntohs(host->port), code));
3954                             host->hostFlags |= VENUSDOWN;
3955                         }
3956                     }
3957                 }
3958             }
3959             H_UNLOCK;
3960             rx_PutConnection(cb_conn);
3961             cb_conn=NULL;
3962             H_LOCK;
3963             host->hostFlags &= ~HWHO_INPROGRESS;
3964         }
3965         h_Unlock_r(host);
3966     }
3967     return 0;
3968
3969 }                               /*CheckHost_r */
3970
3971
3972 /*
3973  * Set VenusDown for any hosts that have not had a call in 15 minutes and
3974  * don't respond to a probe.  Note that VenusDown can only be cleared if
3975  * a message is received from the host (see ServerLWP in file.c).
3976  * Delete hosts that have not had any calls in 1 hour, clients that
3977  * have not had any calls in 15 minutes.
3978  *
3979  * This routine is called roughly every 5 minutes.
3980  */
3981 void
3982 h_CheckHosts(void)
3983 {
3984     afs_uint32 now = FT_ApproxTime();
3985
3986     memset(&zerofid, 0, sizeof(zerofid));
3987     /*
3988      * Send a probe to the workstation if it hasn't been heard from in
3989      * 15 minutes
3990      */
3991     checktime = now - 15 * 60;
3992     clientdeletetime = now - 120 * 60;  /* 2 hours ago */
3993
3994     H_LOCK;
3995     h_Enumerate_r(CheckHost_r, hostList, NULL);
3996     H_UNLOCK;
3997 }                               /*h_CheckHosts */
3998
3999 /*
4000  * This is called with host locked and held. At this point, the
4001  * hostAddrHashTable has an entry for the primary addr/port inserted
4002  * by h_Alloc_r().  No other interfaces should be considered valid.
4003  *
4004  * The addresses in the interfaceAddr list are in host byte order.
4005  */
4006 int
4007 initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
4008 {
4009     int i, j;
4010     int number, count;
4011     afs_uint32 myAddr;
4012     afs_uint16 myPort;
4013     int found;
4014     struct Interface *interface;
4015     char hoststr[16];
4016     char uuidstr[128];
4017     afs_uint16 port7001 = htons(7001);
4018
4019     osi_Assert(host);
4020     osi_Assert(interf);
4021
4022     number = interf->numberOfInterfaces;
4023     myAddr = host->host;        /* current interface address */
4024     myPort = host->port;        /* current port */
4025
4026     ViceLog(125,
4027             ("initInterfaceAddr : host %s:%d numAddr %d\n",
4028               afs_inet_ntoa_r(myAddr, hoststr), ntohs(myPort), number));
4029
4030     /* validation checks */
4031     if (number < 0 || number > AFS_MAX_INTERFACE_ADDR) {
4032         ViceLog(0,
4033                 ("Invalid number of alternate addresses is %d\n", number));
4034         return -1;
4035     }
4036
4037     /*
4038      * The client's notion of its own IP addresses is not reliable.
4039      *
4040      * 1. The client list might contain private address ranges which
4041      *    are likely to be re-used by many clients allocated addresses
4042      *    by a NAT.
4043      *
4044      * 2. The client list will not include any public addresses that
4045      *    are hidden by a NAT.
4046      *
4047      * 3. Private address ranges that are exposed to the server will
4048      *    be obtained from the rx connections that use them.
4049      *
4050      * 4. Lists provided by the client are not necessarily truthful.
4051      *    Many existing clients (UNIX) do not refresh the IP address
4052      *    list as the actual assigned addresses change.  The end result
4053      *    is that they report the initial address list for the lifetime
4054      *    of the process.  In other words, a client can report addresses
4055      *    that they are in fact not using.  Adding these addresses to
4056      *    the host interface list without verification is not only
4057      *    pointless, it is downright dangerous.
4058      *
4059      * We therefore do not add alternate addresses to the addr hash table.
4060      * We only use them for multi-rx callback breaks.
4061      */
4062
4063     /*
4064      * Convert IP addresses to network byte order, and remove
4065      * duplicate and loopback IP addresses from the interface list, and
4066      * determine whether or not the incoming addr/port is
4067      * listed.  Note that if the address matches it is not
4068      * truly a match because the port number for the entries
4069      * in the interface list are port 7001 and the port number
4070      * for this connection might not be 7001.
4071      */
4072     for (i = 0, count = 0, found = 0; i < number; i++) {
4073         if (rx_IsLoopbackAddr(interf->addr_in[i])) {
4074             continue;
4075         }
4076         interf->addr_in[i] = htonl(interf->addr_in[i]);
4077         for (j = 0; j < count; j++) {
4078             if (interf->addr_in[j] == interf->addr_in[i])
4079                 break;
4080         }
4081         if (j == count) {
4082             interf->addr_in[count] = interf->addr_in[i];
4083             if (interf->addr_in[count] == myAddr &&
4084                 port7001 == myPort)
4085                 found = 1;
4086             count++;
4087         }
4088     }
4089
4090     /*
4091      * Allocate and initialize an interface structure for this host.
4092      */
4093     if (found) {
4094         interface = (struct Interface *)
4095             malloc(sizeof(struct Interface) +
4096                    (sizeof(struct AddrPort) * (count - 1)));
4097         if (!interface) {
4098             ViceLogThenPanic(0, ("Failed malloc in initInterfaceAddr_r 1\n"));
4099         }
4100         interface->numberOfInterfaces = count;
4101     } else {
4102         interface = (struct Interface *)
4103             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * count));
4104         if (!interface) {
4105             ViceLogThenPanic(0, ("Failed malloc in initInterfaceAddr_r 2\n"));
4106         }
4107         interface->numberOfInterfaces = count + 1;
4108         interface->interface[count].addr = myAddr;
4109         interface->interface[count].port = myPort;
4110         interface->interface[count].valid = 1;
4111     }
4112
4113     for (i = 0; i < count; i++) {
4114
4115         interface->interface[i].addr = interf->addr_in[i];
4116         /* We store the port as 7001 because the addresses reported by
4117          * TellMeAboutYourself and WhoAreYou RPCs are only valid if they
4118          * are coming from fully connected hosts (no NAT/PATs)
4119          */
4120         interface->interface[i].port = port7001;
4121         interface->interface[i].valid =
4122             (interf->addr_in[i] == myAddr && port7001 == myPort) ? 1 : 0;
4123     }
4124
4125     interface->uuid = interf->uuid;
4126
4127     osi_Assert(!host->interface);
4128     host->interface = interface;
4129
4130     if (LogLevel >= 125) {
4131         afsUUID_to_string(&interface->uuid, uuidstr, 127);
4132
4133         ViceLog(125, ("--- uuid %s\n", uuidstr));
4134         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
4135             ViceLog(125, ("--- alt address %s:%d\n",
4136                           afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
4137                           ntohs(host->interface->interface[i].port)));
4138         }
4139     }
4140
4141     return 0;
4142 }
4143
4144 /* deleted a HashChain structure for this address and host */
4145 /* returns 1 on success */
4146 int
4147 h_DeleteHostFromAddrHashTable_r(afs_uint32 addr, afs_uint16 port,
4148                                 struct host *host)
4149 {
4150     char hoststr[16];
4151     struct h_AddrHashChain **hp, *th;
4152
4153     if (addr == 0 && port == 0)
4154         return 1;
4155
4156     for (hp = &hostAddrHashTable[h_HashIndex(addr)]; (th = *hp);
4157          hp = &th->next) {
4158         osi_Assert(th->hostPtr);
4159         if (th->hostPtr == host && th->addr == addr && th->port == port) {
4160             ViceLog(125, ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT " (%s:%d)\n",
4161                           host, afs_inet_ntoa_r(host->host, hoststr),
4162                           ntohs(host->port)));
4163             *hp = th->next;
4164             free(th);
4165             return 1;
4166         }
4167     }
4168     ViceLog(125,
4169             ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT " (%s:%d) not found\n",
4170              host, afs_inet_ntoa_r(host->host, hoststr),
4171              ntohs(host->port)));
4172     return 0;
4173 }
4174
4175
4176 /*
4177 ** prints out all alternate interface address for the host. The 'level'
4178 ** parameter indicates what level of debugging sets this output
4179 */
4180 void
4181 printInterfaceAddr(struct host *host, int level)
4182 {
4183     int i, number;
4184     char hoststr[16];
4185
4186     if (host->interface) {
4187         /* check alternate addresses */
4188         number = host->interface->numberOfInterfaces;
4189         if (number == 0) {
4190             ViceLog(level, ("no-addresses "));
4191         } else {
4192             for (i = 0; i < number; i++)
4193                 ViceLog(level, ("%s:%d ", afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
4194                                 ntohs(host->interface->interface[i].port)));
4195         }
4196     }
4197     ViceLog(level, ("\n"));
4198 }