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