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