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