Check for HOSTDELETED before h_Hold_r
[openafs.git] / src / viced / host.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  *
9  * Portions Copyright (c) 2006 Sine Nomine Associates
10  */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
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
846     /* if somebody still has this host locked */
847     if (h_NBLock_r(host) != 0) {
848         char hoststr[16];
849         ViceLog(0,
850                 ("Warning:  h_TossStuff_r failed; Host %" AFS_PTR_FMT " (%s:%d) was locked.\n",
851                  host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
852         return;
853     } else {
854         h_Unlock_r(host);
855     }
856
857     /* if somebody still has this host held */
858     /* we must check this _after_ h_NBLock_r, since h_NBLock_r can drop and
859      * reacquire H_LOCK */
860     if (host->refCount > 0) {
861         char hoststr[16];
862         ViceLog(0,
863                 ("Warning:  h_TossStuff_r failed; Host %" AFS_PTR_FMT " (%s:%d) was held.\n",
864                  host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
865         return;
866     }
867
868     /* ASSUMPTION: rxi_FreeConnection() does not yield */
869     for (cp = &host->FirstClient; (client = *cp);) {
870         if ((host->hostFlags & HOSTDELETED) || client->deleted) {
871             int code;
872             ObtainWriteLockNoBlock(&client->lock, code);
873             if (code < 0) {
874                 char hoststr[16];
875                 ViceLog(0,
876                         ("Warning: h_TossStuff_r failed: Host %p (%s:%d) "
877                          "client %p was locked.\n",
878                          host, afs_inet_ntoa_r(host->host, hoststr),
879                          ntohs(host->port), client));
880                 return;
881             }
882                  
883             if (client->refCount) {
884                 char hoststr[16];
885                 ViceLog(0,
886                         ("Warning: h_TossStuff_r failed: Host %p (%s:%d) "
887                          "client %p refcount %d.\n",
888                          host, afs_inet_ntoa_r(host->host, hoststr),
889                          ntohs(host->port), client, client->refCount));
890                 /* This is the same thing we do if the host is locked */
891                 ReleaseWriteLock(&client->lock);
892                 return;
893             }
894             client->CPS.prlist_len = 0;
895             if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
896                 free(client->CPS.prlist_val);
897             client->CPS.prlist_val = NULL;
898             CurrentConnections--;
899             *cp = client->next;
900             ReleaseWriteLock(&client->lock);
901             FreeCE(client);
902         } else
903             cp = &client->next;
904     }
905
906     /* We've just cleaned out all the deleted clients; clear the flag */
907     host->hostFlags &= ~CLIENTDELETED;
908
909     if (host->hostFlags & HOSTDELETED) {
910         register struct rx_connection *rxconn;
911         struct AddrPort hostAddrPort;
912         int i;
913
914         if (host->Console & 1)
915             Console--;
916         if ((rxconn = host->callback_rxcon)) {
917             host->callback_rxcon = (struct rx_connection *)0;
918             rx_DestroyConnection(rxconn);
919         }
920         if (host->hcps.prlist_val)
921             free(host->hcps.prlist_val);
922         host->hcps.prlist_val = NULL;
923         host->hcps.prlist_len = 0;
924         DeleteAllCallBacks_r(host, 1);
925         host->hostFlags &= ~RESETDONE;  /* just to be safe */
926
927         /* if alternate addresses do not exist */
928         if (!(host->interface)) {
929             h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
930         } else {
931             h_DeleteHostFromUuidHashTable_r(host);
932             h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
933             /* delete the hash entry for each valid alternate addresses */
934             for (i = 0; i < host->interface->numberOfInterfaces; i++) {
935                 hostAddrPort = host->interface->interface[i];
936                 /* 
937                  * if the interface addr/port is the primary, we already
938                  * removed it.  If the addr/port is not valid, its not
939                  * in the hash table.
940                  */
941                 if (hostAddrPort.valid &&
942                     (host->host != hostAddrPort.addr ||
943                      host->port != hostAddrPort.port))
944                     h_DeleteHostFromAddrHashTable_r(hostAddrPort.addr, hostAddrPort.port, host);
945             }
946             free(host->interface);
947             host->interface = NULL;
948         }                       /* if alternate address exists */
949
950         h_DeleteList_r(host);   /* remove host from global host List */
951         FreeHT(host);
952     }
953 }                               /*h_TossStuff_r */
954
955
956
957 /* h_Enumerate: Calls (*proc)(host, held, param) for at least each host in the
958  * system at the start of the enumeration (perhaps more).  Hosts may be deleted
959  * (have delete flag set); ditto for clients.  refCount is always incremented
960  * before (*proc) is called.  The param flags is passed to (*proc) as the
961  * param flags, permitting (*proc) to stop the enumeration (BAIL).
962  *
963  * Needed?  Why not always h_Hold_r and h_Release_r in (*proc), or even -never-
964  * h_Hold_r or h_Release_r in (*proc)?
965  *
966  * **The proc should return 0 if the host should be released, 1 if it should
967  * be held after enumeration.
968  */
969 void
970 h_Enumerate(int (*proc) (struct host*, int, void *), void *param)
971 {
972     register struct host *host, **list;
973     register int *flags;
974     register int i, count;
975     int totalCount;
976
977     H_LOCK;
978     if (hostCount == 0) {
979         H_UNLOCK;
980         return;
981     }
982     list = (struct host **)malloc(hostCount * sizeof(struct host *));
983     if (!list) {
984         ViceLog(0, ("Failed malloc in h_Enumerate (list)\n"));
985         assert(0);
986     }
987     flags = (int *)malloc(hostCount * sizeof(int));
988     if (!flags) {
989         ViceLog(0, ("Failed malloc in h_Enumerate (flags)\n"));
990         assert(0);
991     }
992     for (totalCount = count = 0, host = hostList;
993          host && totalCount < hostCount;
994          host = host->next, totalCount++) {
995
996         if (!(host->hostFlags & HOSTDELETED)) {
997             list[count] = host;
998             h_Hold_r(host);
999             count++;
1000         }
1001     }
1002     if (totalCount != hostCount) {
1003         ViceLog(0, ("h_Enumerate found %d of %d hosts\n", totalCount, hostCount));
1004     } else if (host != NULL) {
1005         ViceLog(0, ("h_Enumerate found more than %d hosts\n", hostCount));
1006         ShutDownAndCore(PANIC);
1007     }
1008     H_UNLOCK;
1009     for (i = 0; i < count; i++) {
1010         flags[i] = (*proc) (list[i], flags[i], param);
1011         h_Release_r(list[i]);
1012         /* bail out of the enumeration early */
1013         if (H_ENUMERATE_ISSET_BAIL(flags[i]))
1014             break;
1015     }
1016     free((void *)list);
1017     free((void *)flags);
1018 }       /* h_Enumerate */
1019
1020
1021 /* h_Enumerate_r (revised):
1022  * Calls (*proc)(host, flags, param) for each host in hostList, starting
1023  * at enumstart. Called only under H_LOCK.  Hosts may be deleted (have
1024  * delete flag set); ditto for clients.  refCount is always incremented
1025  * before (*proc) is called.  The param flags is passed to (*proc) as the
1026  * param flags, permitting (*proc) to stop the enumeration (BAIL).
1027  *
1028  * Needed?  Why not always h_Hold_r and h_Release_r in (*proc), or even -never-
1029  * h_Hold_r or h_Release_r in (*proc)?
1030  *
1031  * @note Assumes that hostList is only prepended to, that a host is never
1032  *       inserted into the middle. Otherwise this would not be guaranteed to
1033  *       terminate.
1034  *
1035  * **The proc should return 0 if the host should be released, 1 if it should
1036  * be held after enumeration.
1037  */
1038 void
1039 h_Enumerate_r(int (*proc) (struct host *, int, void *), 
1040               struct host *enumstart, void *param)
1041 {
1042     register struct host *host, *next;
1043     int flags = 0;
1044     int nflags = 0;
1045     int count;
1046     int origHostCount;
1047
1048     if (hostCount == 0) {
1049         return;
1050     }
1051
1052     host = enumstart;
1053     enumstart = NULL;
1054
1055     /* find the first non-deleted host, so we know where to actually start
1056      * enumerating */
1057     for (count = 0; host && count < hostCount; count++) {
1058         if (!(host->hostFlags & HOSTDELETED)) {
1059             enumstart = host;
1060             break;
1061         }
1062         host = host->next;
1063     }
1064     if (!enumstart) {
1065         /* we didn't find a non-deleted host... */
1066
1067         if (host && count >= hostCount) {
1068             /* ...because we found a loop */
1069             ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", hostCount));
1070             ShutDownAndCore(PANIC);
1071         }
1072
1073         /* ...because the hostList is full of deleted hosts */
1074         return;
1075     }
1076
1077     h_Hold_r(enumstart);
1078
1079     /* remember hostCount, lest it change over the potential H_LOCK drop in
1080      * h_Release_r */
1081     origHostCount = hostCount;
1082
1083     for (count = 0, host = enumstart; host && count < origHostCount; host = next, flags = nflags, count++) {
1084         next = host->next;
1085
1086         /* find the next non-deleted host */
1087         while (next && (next->hostFlags & HOSTDELETED)) {
1088             next = next->next;
1089             /* inc count for the skipped-over host */
1090             if (++count > origHostCount) {
1091                 ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", origHostCount));
1092                 ShutDownAndCore(PANIC);
1093             }
1094         }
1095         if (next && !H_ENUMERATE_ISSET_BAIL(flags))
1096             h_Hold_r(next);
1097
1098         if (!(host->hostFlags & HOSTDELETED)) {
1099             flags = (*proc) (host, flags, param);
1100             if (H_ENUMERATE_ISSET_BAIL(flags)) {
1101                 h_Release_r(host); /* this might free up the host */
1102                 break;
1103             }
1104         }
1105         h_Release_r(host); /* this might free up the host */
1106     }
1107     if (host != NULL && count >= origHostCount) {
1108         ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", origHostCount));
1109         ShutDownAndCore(PANIC);
1110     }
1111 }       /*h_Enumerate_r */
1112
1113
1114 /* inserts a new HashChain structure corresponding to this UUID */
1115 void
1116 h_AddHostToUuidHashTable_r(struct afsUUID *uuid, struct host *host)
1117 {
1118     int index;
1119     struct h_UuidHashChain *chain;
1120     char uuid1[128], uuid2[128];
1121     char hoststr[16];
1122
1123     /* hash into proper bucket */
1124     index = h_UuidHashIndex(uuid);
1125
1126     /* don't add the same entry multiple times */
1127     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
1128         if (!chain->hostPtr)
1129             continue;
1130
1131         if (chain->hostPtr->interface && 
1132             afs_uuid_equal(&chain->hostPtr->interface->uuid, uuid)) {
1133             if (LogLevel >= 125) {
1134                 afsUUID_to_string(&chain->hostPtr->interface->uuid, uuid1, 
1135                                   127);
1136                 afsUUID_to_string(uuid, uuid2, 127);
1137                 ViceLog(125, ("h_AddHostToUuidHashTable_r: host %" AFS_PTR_FMT " (uuid %s) exists as %s:%d (uuid %s)\n", 
1138                               host, uuid1,
1139                               afs_inet_ntoa_r(chain->hostPtr->host, hoststr), 
1140                               ntohs(chain->hostPtr->port), uuid2));
1141             }
1142             return;
1143         }
1144     }
1145
1146     /* insert into beginning of list for this bucket */
1147     chain = (struct h_UuidHashChain *)malloc(sizeof(struct h_UuidHashChain));
1148     if (!chain) {
1149         ViceLog(0, ("Failed malloc in h_AddHostToUuidHashTable_r\n"));
1150         assert(0);
1151     }
1152     chain->hostPtr = host;
1153     chain->next = hostUuidHashTable[index];
1154     hostUuidHashTable[index] = chain;
1155          if (LogLevel < 125)
1156                return;
1157      afsUUID_to_string(uuid, uuid2, 127);
1158      ViceLog(125, 
1159              ("h_AddHostToUuidHashTable_r: host %p (%s:%d) added as uuid %s\n",
1160               host, afs_inet_ntoa_r(chain->hostPtr->host, hoststr), 
1161               ntohs(chain->hostPtr->port), uuid2));
1162 }
1163
1164 /* deletes a HashChain structure corresponding to this host */
1165 int
1166 h_DeleteHostFromUuidHashTable_r(struct host *host)
1167 {
1168      int index;
1169      register struct h_UuidHashChain **uhp, *uth;
1170      char uuid1[128];
1171      char hoststr[16];
1172  
1173      if (!host->interface)
1174        return 0;
1175  
1176      /* hash into proper bucket */
1177      index = h_UuidHashIndex(&host->interface->uuid);
1178      
1179      if (LogLevel >= 125)
1180          afsUUID_to_string(&host->interface->uuid, uuid1, 127);
1181      for (uhp = &hostUuidHashTable[index]; (uth = *uhp); uhp = &uth->next) {
1182          assert(uth->hostPtr);
1183          if (uth->hostPtr == host) {
1184              ViceLog(125, 
1185                      ("h_DeleteHostFromUuidHashTable_r: host %" AFS_PTR_FMT " (uuid %s %s:%d)\n",
1186                       host, uuid1, afs_inet_ntoa_r(host->host, hoststr), 
1187                       ntohs(host->port)));
1188              *uhp = uth->next;
1189              free(uth);
1190              return 1;
1191          }
1192      }
1193      ViceLog(125, 
1194              ("h_DeleteHostFromUuidHashTable_r: host %" AFS_PTR_FMT " (uuid %s %s:%d) not found\n",
1195               host, uuid1, afs_inet_ntoa_r(host->host, hoststr), 
1196               ntohs(host->port)));
1197      return 0;
1198 }
1199
1200 /* inserts a new HashChain structure corresponding to this address */
1201 void
1202 h_AddHostToAddrHashTable_r(afs_uint32 addr, afs_uint16 port, struct host *host)
1203 {
1204     int index;
1205     struct h_AddrHashChain *chain;
1206     char hoststr[16];
1207
1208     /* hash into proper bucket */
1209     index = h_HashIndex(addr);
1210
1211     /* don't add the same address:port pair entry multiple times */
1212     for (chain = hostAddrHashTable[index]; chain; chain = chain->next) {
1213         if (chain->addr == addr && chain->port == port) {
1214             if (chain->hostPtr == host) {
1215                 ViceLog(125,
1216                         ("h_AddHostToAddrHashTable_r: host %" AFS_PTR_FMT " (%s:%d) already hashed\n",
1217                           host, afs_inet_ntoa_r(chain->addr, hoststr),
1218                           ntohs(chain->port)));
1219                 return;
1220             }
1221             if (!(chain->hostPtr->hostFlags & HOSTDELETED)) {
1222                 ViceLog(0,
1223                         ("h_AddHostToAddrHashTable_r: refusing to hash host %" AFS_PTR_FMT ", %"
1224                          AFS_PTR_FMT " (%s:%d) already hashed\n",
1225                          host, chain->hostPtr, afs_inet_ntoa_r(chain->addr, hoststr),
1226                           ntohs(chain->port)));
1227                 return;
1228             }
1229         }
1230     }
1231
1232     /* insert into beginning of list for this bucket */
1233     chain = (struct h_AddrHashChain *)malloc(sizeof(struct h_AddrHashChain));
1234     if (!chain) {
1235         ViceLog(0, ("Failed malloc in h_AddHostToAddrHashTable_r\n"));
1236         assert(0);
1237     }
1238     chain->hostPtr = host;
1239     chain->next = hostAddrHashTable[index];
1240     chain->addr = addr;
1241     chain->port = port;
1242     hostAddrHashTable[index] = chain;
1243     ViceLog(125, ("h_AddHostToAddrHashTable_r: host %" AFS_PTR_FMT " added as %s:%d\n",
1244                   host, afs_inet_ntoa_r(addr, hoststr), ntohs(port)));
1245 }
1246
1247 /*
1248  * This is called with host locked and held. 
1249  * It is called to either validate or add an additional interface
1250  * address/port on the specified host.  
1251  *
1252  * All addresses are in network byte order.
1253  */
1254 int
1255 addInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1256 {
1257     int i;
1258     int number;
1259     struct Interface *interface;
1260     char hoststr[16], hoststr2[16];
1261                                                    
1262     assert(host);
1263     assert(host->interface);
1264
1265     /*
1266      * Make sure this address is on the list of known addresses
1267      * for this host.
1268      */
1269     number = host->interface->numberOfInterfaces;
1270     for (i = 0; i < number; i++) {
1271         if (host->interface->interface[i].addr == addr &&
1272              host->interface->interface[i].port == port) {
1273             ViceLog(125, 
1274                     ("addInterfaceAddr : found host %" AFS_PTR_FMT " (%s:%d) adding %s:%d%s\n",
1275                      host, afs_inet_ntoa_r(host->host, hoststr), 
1276                      ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
1277                      ntohs(port), host->interface->interface[i].valid ? "" : 
1278                      ", validating"));
1279      
1280             if (host->interface->interface[i].valid == 0) {
1281                 host->interface->interface[i].valid = 1;
1282                 h_AddHostToAddrHashTable_r(addr, port, host);
1283             }
1284             return 0;
1285         }
1286     }
1287
1288     ViceLog(125, ("addInterfaceAddr : host %" AFS_PTR_FMT " (%s:%d) adding %s:%d\n", 
1289                   host, afs_inet_ntoa_r(host->host, hoststr), 
1290                   ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
1291                   ntohs(port)));
1292     
1293     interface = (struct Interface *)
1294         malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * number));
1295     if (!interface) {
1296         ViceLog(0, ("Failed malloc in addInterfaceAddr_r\n"));
1297         assert(0);
1298     }
1299     interface->numberOfInterfaces = number + 1;
1300     interface->uuid = host->interface->uuid;
1301     for (i = 0; i < number; i++)
1302         interface->interface[i] = host->interface->interface[i];
1303     
1304     /* Add the new valid interface */
1305     interface->interface[number].addr = addr;
1306     interface->interface[number].port = port;
1307     interface->interface[number].valid = 1;
1308     h_AddHostToAddrHashTable_r(addr, port, host);
1309     free(host->interface);
1310     host->interface = interface;
1311     
1312     return 0;
1313 }
1314
1315
1316 /*
1317  * This is called with host locked and held.
1318  *
1319  * All addresses are in network byte order.
1320  */
1321 int
1322 removeInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1323 {
1324     int i;
1325     int number;
1326     struct Interface *interface;
1327     char hoststr[16], hoststr2[16];
1328
1329     assert(host);
1330     assert(host->interface);
1331
1332     ViceLog(125, ("removeInterfaceAddr : host %" AFS_PTR_FMT " (%s:%d) addr %s:%d\n", 
1333                   host, afs_inet_ntoa_r(host->host, hoststr), 
1334                   ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
1335                   ntohs(port)));
1336
1337     /*
1338      * Make sure this address is on the list of known addresses
1339      * for this host.
1340      */
1341     interface = host->interface;
1342     number = host->interface->numberOfInterfaces;
1343     for (i = 0; i < number; i++) {
1344         if (interface->interface[i].addr == addr &&
1345             interface->interface[i].port == port) {
1346             if (interface->interface[i].valid)
1347                 h_DeleteHostFromAddrHashTable_r(addr, port, host);
1348             number--;
1349             for (; i < number; i++) {
1350                 interface->interface[i] = interface->interface[i+1];
1351             }
1352             interface->numberOfInterfaces = number;
1353             return 0;
1354         }
1355     }   
1356     /* not found */
1357     return 0;
1358 }
1359
1360 /*
1361  * This is called with host locked and held.
1362  *
1363  * All addresses are in network byte order.
1364  */
1365 int
1366 invalidateInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1367 {
1368     int i;
1369     int number;
1370     struct Interface *interface;
1371     char hoststr[16], hoststr2[16];
1372     
1373     assert(host);
1374     assert(host->interface);
1375     
1376     ViceLog(125, ("invalidateInterfaceAddr : host %" AFS_PTR_FMT " (%s:%d) addr %s:%d\n", 
1377                   host, afs_inet_ntoa_r(host->host, hoststr), 
1378                   ntohs(host->port), afs_inet_ntoa_r(addr, hoststr2), 
1379                   ntohs(port)));
1380     
1381     /*
1382      * Make sure this address is on the list of known addresses
1383      * for this host.
1384      */
1385     interface = host->interface;
1386     number = host->interface->numberOfInterfaces;
1387     for (i = 0; i < number; i++) {
1388         if (interface->interface[i].addr == addr &&
1389             interface->interface[i].port == port) {
1390             if (interface->interface[i].valid) {
1391                 h_DeleteHostFromAddrHashTable_r(addr, port, host);
1392                 interface->interface[i].valid = 0;
1393             }
1394             return 0;
1395         }
1396     }
1397     
1398     /* not found */
1399     return 0;
1400 }
1401
1402 /*
1403  * This is called with host locked and held.  This function differs
1404  * from removeInterfaceAddr_r in that it is called when the address
1405  * is being removed from the host regardless of whether or not there
1406  * is an interface list for the host.  This function will delete the
1407  * host if there are no addresses left on it.
1408  *
1409  * All addresses are in network byte order.
1410  */
1411 int
1412 removeAddress_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1413 {
1414     int i;
1415     char hoststr[16], hoststr2[16];
1416     struct rx_connection *rxconn;
1417
1418     if (!host->interface || host->interface->numberOfInterfaces == 1) {
1419         if (host->host == addr && host->port == port) {
1420             ViceLog(25,
1421                     ("Removing only address for host %" AFS_PTR_FMT " (%s:%d), deleting host.\n",
1422                      host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1423             host->hostFlags |= HOSTDELETED;
1424             /* 
1425              * Do not remove the primary addr/port from the hash table.
1426              * It will be ignored due to the HOSTDELETED flag and will
1427              * be removed when h_TossStuff_r() cleans up the HOSTDELETED
1428              * host.  Removing it here will only result in a search for 
1429              * the host/addr/port in the hash chain which will fail.
1430              */
1431         } else {
1432             ViceLog(0,
1433                     ("Removing address that does not belong to host %" AFS_PTR_FMT " (%s:%d).\n",
1434                      host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1435         }
1436     } else {
1437         if (host->host == addr && host->port == port)  {
1438             removeInterfaceAddr_r(host, addr, port);
1439
1440             for (i=0; i < host->interface->numberOfInterfaces; i++) {
1441                 if (host->interface->interface[i].valid) {
1442                     ViceLog(25,
1443                              ("Removed address for host %" AFS_PTR_FMT " (%s:%d), new primary interface %s:%d.\n",
1444                                host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
1445                                afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr2), 
1446                                ntohs(host->interface->interface[i].port)));
1447                     host->host = host->interface->interface[i].addr;
1448                     host->port = host->interface->interface[i].port;
1449                     h_AddHostToAddrHashTable_r(host->host, host->port, host);
1450                     break;
1451                 }
1452             }
1453
1454             if (i == host->interface->numberOfInterfaces) {
1455                 ViceLog(25,
1456                          ("Removed only address for host %" AFS_PTR_FMT " (%s:%d), no valid alternate interfaces, deleting host.\n",
1457                            host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1458                 host->hostFlags |= HOSTDELETED;
1459                 /* addr/port was removed from the hash table */
1460                 host->host = 0;
1461                 host->port = 0;
1462             } else {
1463                 rxconn = host->callback_rxcon;
1464                 host->callback_rxcon = NULL;
1465
1466                 if (rxconn) {
1467                     rx_DestroyConnection(rxconn);
1468                     rxconn = NULL;
1469                 }
1470
1471                 if (!sc)
1472                     sc = rxnull_NewClientSecurityObject();
1473                 host->callback_rxcon =
1474                     rx_NewConnection(host->host, host->port, 1, sc, 0);
1475                 rx_SetConnDeadTime(host->callback_rxcon, 50);
1476                 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1477             }
1478         } else {
1479             /* not the primary addr/port, just invalidate it */
1480             invalidateInterfaceAddr_r(host, addr, port);
1481         }
1482     }
1483
1484     return 0;
1485 }
1486 static int
1487 h_threadquota(int waiting) 
1488 {
1489     if (lwps > 64) {
1490         if (waiting > 5)
1491             return 1;
1492     } else if (lwps > 32) {
1493         if (waiting > 4)
1494             return 1;
1495     } else if (lwps > 16) {
1496         if (waiting > 3)
1497             return 1;
1498     } else {
1499         if (waiting > 2)
1500             return 1;
1501     }
1502     return 0;
1503 }
1504
1505 /* If found, host is returned with refCount incremented */
1506 struct host *
1507 h_GetHost_r(struct rx_connection *tcon)
1508 {
1509     struct host *host;
1510     struct host *oldHost;
1511     int code;
1512     struct interfaceAddr interf;
1513     int interfValid = 0;
1514     struct Identity *identP = NULL;
1515     afs_uint32 haddr;
1516     afs_uint16 hport;
1517     char hoststr[16], hoststr2[16];
1518     Capabilities caps;
1519     struct rx_connection *cb_conn = NULL;
1520     struct rx_connection *cb_in = NULL;
1521
1522     caps.Capabilities_val = NULL;
1523
1524     haddr = rxr_HostOf(tcon);
1525     hport = rxr_PortOf(tcon);
1526   retry:
1527     if (cb_in) {
1528         rx_DestroyConnection(cb_in);
1529         cb_in = NULL;
1530     }
1531     if (caps.Capabilities_val)
1532         free(caps.Capabilities_val);
1533     caps.Capabilities_val = NULL;
1534     caps.Capabilities_len = 0;
1535
1536     code = 0;
1537     if (h_Lookup_r(haddr, hport, &host))
1538         return 0;
1539     identP = (struct Identity *)rx_GetSpecific(tcon, rxcon_ident_key);
1540     if (host && !identP && !(host->Console & 1)) {
1541         /* This is a new connection, and we already have a host
1542          * structure for this address. Verify that the identity
1543          * of the caller matches the identity in the host structure.
1544          */
1545         if ((host->hostFlags & HWHO_INPROGRESS) && 
1546             h_threadquota(host->lock.num_waiting)) {
1547                 h_Release_r(host);
1548             host = NULL;
1549             goto gethost_out;
1550         }
1551         h_Lock_r(host);
1552         if (!(host->hostFlags & ALTADDR) ||
1553             (host->hostFlags & HOSTDELETED)) {
1554             /* Another thread is doing initialization
1555              * or this host was deleted while we
1556              * waited for the lock. */
1557             h_Unlock_r(host);
1558             ViceLog(125,
1559                     ("Host %" AFS_PTR_FMT " (%s:%d) starting h_Lookup again\n",
1560                      host, afs_inet_ntoa_r(host->host, hoststr),
1561                      ntohs(host->port)));
1562             h_Release_r(host);
1563             goto retry;
1564         }
1565         host->hostFlags |= HWHO_INPROGRESS;
1566         host->hostFlags &= ~ALTADDR;
1567
1568         /* We received a new connection from an IP address/port
1569          * that is associated with 'host' but the address/port of
1570          * the callback connection does not have to match it.
1571          * If there is a match, we can use the existing callback
1572          * connection to verify the UUID.  If they do not match
1573          * we need to use a new callback connection to verify the
1574          * UUID of the incoming caller and perhaps use the old 
1575          * callback connection to verify that the old address/port
1576          * is still valid.
1577          */
1578         
1579         cb_conn = host->callback_rxcon;
1580         rx_GetConnection(cb_conn);
1581         H_UNLOCK;
1582         if (haddr == host->host && hport == host->port) {
1583             /* The existing callback connection matches the 
1584              * incoming connection so just use it.
1585              */
1586             code =
1587                 RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1588             if (code == RXGEN_OPCODE)
1589                 code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1590         } else {
1591             /* We do not have a match.  Create a new connection
1592              * for the new addr/port and use multi_Rx to probe
1593              * both of them simultaneously.
1594              */
1595             if (!sc)
1596                 sc = rxnull_NewClientSecurityObject();
1597             cb_in = rx_NewConnection(haddr, hport, 1, sc, 0);
1598             rx_SetConnDeadTime(cb_in, 50);
1599             rx_SetConnHardDeadTime(cb_in, AFS_HARDDEADTIME);
1600             
1601             code =
1602                 RXAFSCB_TellMeAboutYourself(cb_in, &interf, &caps);
1603             if (code == RXGEN_OPCODE)
1604                 code = RXAFSCB_WhoAreYou(cb_in, &interf);
1605         }
1606         rx_PutConnection(cb_conn);
1607         cb_conn=NULL;
1608         H_LOCK;
1609         if ((code == RXGEN_OPCODE) || 
1610             ((code == 0) && (afs_uuid_equal(&interf.uuid, &nulluuid)))) {
1611             identP = (struct Identity *)malloc(sizeof(struct Identity));
1612             if (!identP) {
1613                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1614                 assert(0);
1615             }
1616             identP->valid = 0;
1617             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1618             if (cb_in == NULL) {
1619                 /* The host on this connection was unable to respond to 
1620                  * the WhoAreYou. We will treat this as a new connection
1621                  * from the existing host. The worst that can happen is
1622                  * that we maintain some extra callback state information */
1623                 if (host->interface) {
1624                     ViceLog(0,
1625                             ("Host %" AFS_PTR_FMT " (%s:%d) used to support WhoAreYou, deleting.\n",
1626                              host, 
1627                              afs_inet_ntoa_r(host->host, hoststr),
1628                              ntohs(host->port)));
1629                     host->hostFlags |= HOSTDELETED;
1630                     host->hostFlags &= ~HWHO_INPROGRESS;
1631                     h_Unlock_r(host);
1632                     h_Release_r(host);
1633                     host = NULL;
1634                     goto retry;
1635                 }
1636             } else {
1637                 /* The incoming connection does not support WhoAreYou but
1638                  * the original one might have.  Use removeAddress_r() to
1639                  * remove this addr/port from the host that was found.
1640                  * If there are no more addresses left for the host it 
1641                  * will be deleted.  Then we retry.
1642                  */
1643                 removeAddress_r(host, haddr, hport);
1644                 host->hostFlags &= ~HWHO_INPROGRESS;
1645                 host->hostFlags |= ALTADDR;
1646                 h_Unlock_r(host);
1647                 h_Release_r(host);
1648                 host = NULL;
1649                 goto retry;
1650             }
1651         } else if (code == 0) {
1652             interfValid = 1;
1653             identP = (struct Identity *)malloc(sizeof(struct Identity));
1654             if (!identP) {
1655                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1656                 assert(0);
1657             }
1658             identP->valid = 1;
1659             identP->uuid = interf.uuid;
1660             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1661             /* Check whether the UUID on this connection matches
1662              * the UUID in the host structure. If they don't match
1663              * then this is not the same host as before. */
1664             if (!host->interface
1665                 || !afs_uuid_equal(&interf.uuid, &host->interface->uuid)) {
1666                 if (cb_in) {
1667                         ViceLog(25,
1668                                         ("Uuid doesn't match connection (%s:%d).\n",
1669                                          afs_inet_ntoa_r(haddr, hoststr), ntohs(hport)));
1670                         removeAddress_r(host, haddr, hport);
1671                 } else {
1672                     ViceLog(25,
1673                             ("Uuid doesn't match host %" AFS_PTR_FMT " (%s:%d).\n",
1674                              host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1675                     
1676                     removeAddress_r(host, host->host, host->port);
1677                 }
1678                 host->hostFlags &= ~HWHO_INPROGRESS;
1679                 host->hostFlags |= ALTADDR;
1680                 h_Unlock_r(host);
1681                 h_Release_r(host);
1682                 host = NULL;
1683                 goto retry;
1684             } else if (cb_in) {
1685                 /* the UUID matched the client at the incoming addr/port 
1686                  * but this is not the address of the active callback 
1687                  * connection.  Try that connection and see if the client
1688                  * is still there and if the reported UUID is the same.
1689                  */
1690                 int code2;
1691                 afsUUID uuid = host->interface->uuid;
1692                 cb_conn = host->callback_rxcon;
1693                 rx_GetConnection(cb_conn);
1694                 rx_SetConnDeadTime(cb_conn, 2);
1695                 rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1696                 H_UNLOCK;
1697                 code2 = RXAFSCB_ProbeUuid(cb_conn, &uuid);
1698                 H_LOCK;
1699                 rx_SetConnDeadTime(cb_conn, 50);
1700                 rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1701                 rx_PutConnection(cb_conn);
1702                 cb_conn=NULL;
1703                 if (code2) {
1704                     /* The primary address is either not responding or
1705                      * is not the client we are looking for.  Need to
1706                      * remove the primary address and add swap in the new 
1707                      * callback connection, and destroy the old one.
1708                      */
1709                     struct rx_connection *rxconn;
1710                     ViceLog(0,("CB: ProbeUuid for host %" AFS_PTR_FMT " (%s:%d) failed %d\n",
1711                                host, 
1712                                afs_inet_ntoa_r(host->host, hoststr),
1713                                ntohs(host->port),code2));
1714
1715                     /* 
1716                      * make sure we add and then remove.  otherwise, we
1717                      * might end up with no valid interfaces after the 
1718                      * remove and the host will have been marked deleted.
1719                      */
1720                     addInterfaceAddr_r(host, haddr, hport);
1721                     removeInterfaceAddr_r(host, host->host, host->port);
1722                     host->host = haddr;
1723                     host->port = hport;
1724                     rxconn = host->callback_rxcon;
1725                     host->callback_rxcon = cb_in;
1726                     cb_in = NULL;
1727                     
1728                     if (rxconn) {
1729                         /*
1730                          * If rx_DestroyConnection calls h_FreeConnection we
1731                          * will deadlock on the host_glock_mutex. Work around
1732                          * the problem by unhooking the client from the
1733                          * connection before destroying the connection.
1734                          */
1735                         rx_SetSpecific(rxconn, rxcon_client_key, (void *)0);
1736                         rx_DestroyConnection(rxconn);
1737                     }
1738                 }
1739             }
1740         } else {
1741             if (cb_in) {
1742                 /* A callback to the incoming connection address is failing.  
1743                  * Assume that the addr/port is no longer associated with the host
1744                  * returned by h_Lookup_r.
1745                  */
1746                 ViceLog(0,
1747                         ("CB: WhoAreYou failed for connection (%s:%d) , error %d\n",
1748                          afs_inet_ntoa_r(haddr, hoststr), ntohs(hport), code));
1749                 removeAddress_r(host, haddr, hport);
1750                 host->hostFlags &= ~HWHO_INPROGRESS;
1751                 host->hostFlags |= ALTADDR;
1752                 h_Unlock_r(host);
1753                 h_Release_r(host);
1754                 host = NULL;
1755                 rx_DestroyConnection(cb_in);
1756                 cb_in = NULL;
1757                 goto gethost_out;
1758             } else {
1759                 ViceLog(0,
1760                         ("CB: WhoAreYou failed for host %" AFS_PTR_FMT " (%s:%d), error %d\n",
1761                          host, afs_inet_ntoa_r(host->host, hoststr),
1762                          ntohs(host->port), code));
1763                 host->hostFlags |= VENUSDOWN;
1764             }
1765         }
1766         if (caps.Capabilities_val
1767             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
1768             host->hostFlags |= HERRORTRANS;
1769         else
1770             host->hostFlags &= ~(HERRORTRANS);
1771         host->hostFlags |= ALTADDR;
1772         host->hostFlags &= ~HWHO_INPROGRESS;
1773         h_Unlock_r(host);
1774     } else if (host) {
1775         if (!(host->hostFlags & ALTADDR)) {
1776             /* another thread is doing the initialisation */
1777             ViceLog(125,
1778                     ("Host %" AFS_PTR_FMT " (%s:%d) waiting for host-init to complete\n",
1779                      host, afs_inet_ntoa_r(host->host, hoststr),
1780                      ntohs(host->port)));
1781             h_Lock_r(host);
1782             h_Unlock_r(host);
1783             ViceLog(125,
1784                     ("Host %" AFS_PTR_FMT " (%s:%d) starting h_Lookup again\n",
1785                      host, afs_inet_ntoa_r(host->host, hoststr),
1786                      ntohs(host->port)));
1787             h_Release_r(host);
1788             goto retry;
1789         }
1790         /* We need to check whether the identity in the host structure
1791          * matches the identity on the connection. If they don't match
1792          * then treat this a new host. */
1793         if (!(host->Console & 1)
1794             && ((!identP->valid && host->interface)
1795                 || (identP->valid && !host->interface)
1796                 || (identP->valid
1797                     && !afs_uuid_equal(&identP->uuid,
1798                                        &host->interface->uuid)))) {
1799             char uuid1[128], uuid2[128];
1800             if (identP->valid)
1801                 afsUUID_to_string(&identP->uuid, uuid1, 127);
1802             if (host->interface)
1803                 afsUUID_to_string(&host->interface->uuid, uuid2, 127);
1804             ViceLog(0,
1805                     ("CB: new identity for host %p (%s:%d), "
1806                      "deleting(%x %p %s %s)\n",
1807                      host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
1808                      identP->valid, host->interface,
1809                      identP->valid ? uuid1 : "no_uuid",
1810                      host->interface ? uuid2 : "no_uuid"));
1811
1812             /* The host in the cache is not the host for this connection */
1813             h_Lock_r(host);
1814             host->hostFlags |= HOSTDELETED;
1815             h_Unlock_r(host);
1816             h_Release_r(host);
1817             goto retry;
1818         }
1819     } else {
1820         host = h_Alloc_r(tcon); /* returned held and locked */
1821         h_gethostcps_r(host, FT_ApproxTime());
1822         if (!(host->Console & 1)) {
1823             int pident = 0;
1824             cb_conn = host->callback_rxcon;
1825             rx_GetConnection(cb_conn);
1826             host->hostFlags |= HWHO_INPROGRESS;
1827             H_UNLOCK;
1828             code =
1829                 RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1830             if (code == RXGEN_OPCODE)
1831                 code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1832             rx_PutConnection(cb_conn);
1833             cb_conn=NULL;
1834             H_LOCK;
1835             if ((code == RXGEN_OPCODE) || 
1836                 ((code == 0) && (afs_uuid_equal(&interf.uuid, &nulluuid)))) {
1837                 if (!identP)
1838                     identP =
1839                         (struct Identity *)malloc(sizeof(struct Identity));
1840                 else
1841                     pident = 1;
1842
1843                 if (!identP) {
1844                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1845                     assert(0);
1846                 }
1847                 identP->valid = 0;
1848                 if (!pident)
1849                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1850                 ViceLog(25,
1851                         ("Host %" AFS_PTR_FMT " (%s:%d) does not support WhoAreYou.\n",
1852                          host, afs_inet_ntoa_r(host->host, hoststr),
1853                          ntohs(host->port)));
1854                 code = 0;
1855             } else if (code == 0) {
1856                 if (!identP)
1857                     identP =
1858                         (struct Identity *)malloc(sizeof(struct Identity));
1859                 else
1860                     pident = 1;
1861
1862                 if (!identP) {
1863                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1864                     assert(0);
1865                 }
1866                 identP->valid = 1;
1867                 interfValid = 1;
1868                 identP->uuid = interf.uuid;
1869                 if (!pident)
1870                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1871                 ViceLog(25,
1872                         ("WhoAreYou success on host %" AFS_PTR_FMT " (%s:%d)\n",
1873                          host, afs_inet_ntoa_r(host->host, hoststr),
1874                          ntohs(host->port)));
1875             }
1876             if (code == 0 && !identP->valid) {
1877                 cb_conn = host->callback_rxcon;
1878                 rx_GetConnection(cb_conn);
1879                 H_UNLOCK;
1880                 code = RXAFSCB_InitCallBackState(cb_conn);
1881                 rx_PutConnection(cb_conn);
1882                 cb_conn=NULL;
1883                 H_LOCK;
1884             } else if (code == 0) {
1885                 oldHost = h_LookupUuid_r(&identP->uuid);
1886                 if (oldHost) {
1887                     h_Hold_r(oldHost);
1888                     h_Lock_r(oldHost);
1889
1890                     if (oldHost->hostFlags & HOSTDELETED) {
1891                         h_Unlock_r(oldHost);
1892                         h_Release_r(oldHost);
1893                         oldHost = NULL;
1894                     }
1895                 }
1896
1897                 if (oldHost) {
1898                     int probefail = 0;
1899
1900                     oldHost->hostFlags |= HWHO_INPROGRESS;
1901
1902                     if (oldHost->interface) {
1903                         int code2;
1904                         afsUUID uuid = oldHost->interface->uuid;
1905                         cb_conn = oldHost->callback_rxcon;
1906                         rx_GetConnection(cb_conn);
1907                         rx_SetConnDeadTime(cb_conn, 2);
1908                         rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1909                         H_UNLOCK;
1910                         code2 = RXAFSCB_ProbeUuid(cb_conn, &uuid);
1911                         H_LOCK;
1912                         rx_SetConnDeadTime(cb_conn, 50);
1913                         rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME);
1914                         rx_PutConnection(cb_conn);
1915                         cb_conn=NULL;
1916                         if (code2) {
1917                             /* The primary address is either not responding or
1918                              * is not the client we are looking for.  
1919                              * MultiProbeAlternateAddress_r() will remove the
1920                              * alternate interfaces that do not have the same
1921                              * Uuid. */
1922                             ViceLog(0,("CB: ProbeUuid for host %" AFS_PTR_FMT " (%s:%d) failed %d\n",
1923                                          oldHost, 
1924                                          afs_inet_ntoa_r(oldHost->host, hoststr),
1925                                          ntohs(oldHost->port),code2));
1926                             MultiProbeAlternateAddress_r(oldHost);
1927                             probefail = 1;
1928                         }
1929                     } else {
1930                         probefail = 1;
1931                     }
1932
1933                     /* This is a new address for an existing host. Update
1934                      * the list of interfaces for the existing host and
1935                      * delete the host structure we just allocated. */
1936
1937                     /* prevent warnings while manipulating interface lists */
1938                     host->hostFlags |= HOSTDELETED;
1939
1940                     if (oldHost->host != haddr || oldHost->port != hport) {
1941                         struct rx_connection *rxconn;
1942
1943                         ViceLog(25,
1944                                  ("CB: Host %" AFS_PTR_FMT " (%s:%d) has new addr %s:%d\n",
1945                                    oldHost, 
1946                                    afs_inet_ntoa_r(oldHost->host, hoststr2),
1947                                    ntohs(oldHost->port),
1948                                    afs_inet_ntoa_r(haddr, hoststr),
1949                                    ntohs(hport)));
1950                         /* 
1951                          * add then remove.  otherwise the host may get marked
1952                          * deleted if we removed the only valid address.
1953                          */
1954                         addInterfaceAddr_r(oldHost, haddr, hport);
1955                         if (probefail || oldHost->host == haddr) {
1956                             /* 
1957                              * The probe failed which means that the old 
1958                              * address is either unreachable or is not the 
1959                              * same host we were just contacted by.  We will 
1960                              * also remove addresses if only the port has 
1961                              * changed because that indicates the client
1962                              * is behind a NAT. 
1963                              */
1964                             removeInterfaceAddr_r(oldHost, oldHost->host, oldHost->port);
1965                         } else {
1966                             int i;
1967                             struct Interface *interface = oldHost->interface;
1968                             int number = oldHost->interface->numberOfInterfaces;
1969                             for (i = 0; i < number; i++) {
1970                                 if (interface->interface[i].addr == haddr &&
1971                                     interface->interface[i].port != hport) {
1972                                     /* 
1973                                      * We have just been contacted by a client
1974                                      * that has been seen from behind a NAT 
1975                                      * and at least one other address.
1976                                      */
1977                                     removeInterfaceAddr_r(oldHost, haddr, 
1978                                                           interface->interface[i].port);
1979                                     break;
1980                                 }
1981                             }
1982                         }
1983                         h_AddHostToAddrHashTable_r(haddr, hport, oldHost);
1984                         oldHost->host = haddr;
1985                         oldHost->port = hport;
1986                         rxconn = oldHost->callback_rxcon;
1987                         oldHost->callback_rxcon = host->callback_rxcon;
1988                         host->callback_rxcon = rxconn;
1989                         
1990                         /* don't destroy rxconn here; let h_TossStuff_r
1991                          * take care of that via h_Release_r below */
1992                     }
1993                     host->hostFlags &= ~HWHO_INPROGRESS;
1994                     h_Unlock_r(host);
1995                     /* release host because it was allocated by h_Alloc_r */
1996                     h_Release_r(host);
1997                     host = oldHost;
1998                     /* the new host is held and locked */
1999                 } else {
2000                     /* This really is a new host */
2001                     h_AddHostToUuidHashTable_r(&identP->uuid, host);
2002                     cb_conn = host->callback_rxcon;
2003                     rx_GetConnection(cb_conn);          
2004                     H_UNLOCK;
2005                     code =
2006                         RXAFSCB_InitCallBackState3(cb_conn,
2007                                                    &FS_HostUUID);
2008                     rx_PutConnection(cb_conn);
2009                     cb_conn=NULL;
2010                     H_LOCK;
2011                     if (code == 0) {
2012                         ViceLog(25,
2013                                 ("InitCallBackState3 success on host %" AFS_PTR_FMT " (%s:%d)\n",
2014                                  host, afs_inet_ntoa_r(host->host, hoststr),
2015                                  ntohs(host->port)));
2016                         assert(interfValid == 1);
2017                         initInterfaceAddr_r(host, &interf);
2018                     }
2019                 }
2020             }
2021             if (code) {
2022                 ViceLog(0,
2023                         ("CB: RCallBackConnectBack failed for %" AFS_PTR_FMT " (%s:%d)\n",
2024                          host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
2025                 host->hostFlags |= VENUSDOWN;
2026             } else {
2027                 ViceLog(125,
2028                         ("CB: RCallBackConnectBack succeeded for %" AFS_PTR_FMT " (%s:%d)\n",
2029                          host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
2030                 host->hostFlags |= RESETDONE;
2031             }
2032         }
2033         if (caps.Capabilities_val
2034             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
2035             host->hostFlags |= HERRORTRANS;
2036         else
2037             host->hostFlags &= ~(HERRORTRANS);
2038         host->hostFlags |= ALTADDR;     /* host structure initialization complete */
2039         host->hostFlags &= ~HWHO_INPROGRESS;
2040         h_Unlock_r(host);
2041     }
2042
2043  gethost_out:
2044     if (caps.Capabilities_val)
2045         free(caps.Capabilities_val);
2046     caps.Capabilities_val = NULL;
2047     caps.Capabilities_len = 0;
2048     if (cb_in) {
2049         rx_DestroyConnection(cb_in);
2050         cb_in = NULL;
2051     }
2052     return host;
2053
2054 }                               /*h_GetHost_r */
2055
2056
2057 static char localcellname[PR_MAXNAMELEN + 1];
2058 char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
2059 int  num_lrealms = -1;
2060
2061 /* not reentrant */
2062 void
2063 h_InitHostPackage(void)
2064 {
2065     memset(&nulluuid, 0, sizeof(afsUUID));
2066     afsconf_GetLocalCell(confDir, localcellname, PR_MAXNAMELEN);
2067     if (num_lrealms == -1) {
2068         int i;
2069         for (i=0; i<AFS_NUM_LREALMS; i++) {
2070             if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
2071                 break;
2072         }
2073
2074         if (i == 0) {
2075             ViceLog(0,
2076                     ("afs_krb_get_lrealm failed, using %s.\n",
2077                      localcellname));
2078             strncpy(local_realms[0], localcellname, AFS_REALM_SZ);
2079             num_lrealms = i =1;
2080         } else {
2081             num_lrealms = i;
2082         }
2083
2084         /* initialize the rest of the local realms to nullstring for debugging */
2085         for (; i<AFS_NUM_LREALMS; i++)
2086             local_realms[i][0] = '\0';
2087     }
2088     rxcon_ident_key = rx_KeyCreate((rx_destructor_t) free);
2089     rxcon_client_key = rx_KeyCreate((rx_destructor_t) 0);
2090 #ifdef AFS_PTHREAD_ENV
2091     assert(pthread_mutex_init(&host_glock_mutex, NULL) == 0);
2092 #endif /* AFS_PTHREAD_ENV */
2093 }
2094
2095 static int
2096 MapName_r(char *aname, char *acell, afs_int32 * aval)
2097 {
2098     namelist lnames;
2099     idlist lids;
2100     afs_int32 code;
2101     afs_int32 anamelen, cnamelen;
2102     int foreign = 0;
2103     char *tname;
2104
2105     anamelen = strlen(aname);
2106     if (anamelen >= PR_MAXNAMELEN)
2107         return -1;              /* bad name -- caller interprets this as anonymous, but retries later */
2108
2109     lnames.namelist_len = 1;
2110     lnames.namelist_val = (prname *) aname;     /* don't malloc in the common case */
2111     lids.idlist_len = 0;
2112     lids.idlist_val = NULL;
2113
2114     cnamelen = strlen(acell);
2115     if (cnamelen) {
2116         if (afs_is_foreign_ticket_name(aname, NULL, acell, localcellname)) {
2117             ViceLog(2,
2118                     ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealms={%s,%s,%s,%s}\n",
2119                     acell, localcellname, local_realms[0],local_realms[1],local_realms[2],local_realms[3]));
2120             if ((anamelen + cnamelen + 1) >= PR_MAXNAMELEN) {
2121                 ViceLog(2,
2122                         ("MapName: Name too long, using AnonymousID for %s@%s\n",
2123                          aname, acell));
2124                 *aval = AnonymousID;
2125                 return 0;
2126             }
2127             foreign = 1;        /* attempt cross-cell authentication */
2128             tname = (char *)malloc(PR_MAXNAMELEN);
2129             if (!tname) {
2130                 ViceLog(0, ("Failed malloc in MapName_r\n"));
2131                 assert(0);
2132             }
2133             strcpy(tname, aname);
2134             tname[anamelen] = '@';
2135             strcpy(tname + anamelen + 1, acell);
2136             lnames.namelist_val = (prname *) tname;
2137         }
2138     }
2139
2140     H_UNLOCK;
2141     code = hpr_NameToId(&lnames, &lids);
2142     H_LOCK;
2143     if (code == 0) {
2144         if (lids.idlist_val) {
2145             *aval = lids.idlist_val[0];
2146             if (*aval == AnonymousID) {
2147                 ViceLog(2,
2148                         ("MapName: NameToId on %s returns anonymousID\n",
2149                          lnames.namelist_val[0]));
2150             }
2151             free(lids.idlist_val);      /* return parms are not malloced in stub if server proc aborts */
2152         } else {
2153             ViceLog(0,
2154                     ("MapName: NameToId on '%s' is unknown\n",
2155                      lnames.namelist_val[0]));
2156             code = -1;
2157         }
2158     }
2159
2160     if (foreign) {
2161         free(lnames.namelist_val);      /* We allocated this above, so we must free it now. */
2162     }
2163     return code;
2164 }
2165
2166 /*MapName*/
2167
2168
2169 /* NOTE: this returns the client with a Write lock and a refCount */
2170 struct client *
2171 h_ID2Client(afs_int32 vid)
2172 {
2173     register struct client *client;
2174     register struct host *host;
2175     int count;
2176
2177     H_LOCK;
2178     for (count = 0, host = hostList; host && count < hostCount; host = host->next, count++) {
2179         if (host->hostFlags & HOSTDELETED)
2180             continue;
2181         for (client = host->FirstClient; client; client = client->next) {
2182             if (!client->deleted && client->ViceId == vid) {
2183                 client->refCount++;
2184                 H_UNLOCK;
2185                 ObtainWriteLock(&client->lock);
2186                 return client;
2187             }
2188         }
2189     }
2190     if (count != hostCount) {
2191         ViceLog(0, ("h_ID2Client found %d of %d hosts\n", count, hostCount));
2192     } else if (host != NULL) {
2193         ViceLog(0, ("h_ID2Client found more than %d hosts\n", hostCount));
2194         ShutDownAndCore(PANIC);
2195     }
2196
2197     H_UNLOCK;
2198     return NULL;
2199 }
2200
2201 /*
2202  * Called by the server main loop.  Returns a h_Held client, which must be
2203  * released later the main loop.  Allocates a client if the matching one
2204  * isn't around. The client is returned with its reference count incremented
2205  * by one. The caller must call h_ReleaseClient_r when finished with
2206  * the client.
2207  *
2208  * The refCount on client->host is returned incremented.  h_ReleaseClient_r
2209  * does not decrement the refCount on client->host.
2210  */
2211 struct client *
2212 h_FindClient_r(struct rx_connection *tcon)
2213 {
2214     register struct client *client;
2215     struct host *host = NULL;
2216     struct client *oldClient;
2217     afs_int32 viceid = 0;
2218     afs_int32 expTime;
2219     afs_int32 code;
2220     int authClass;
2221 #if (64-MAXKTCNAMELEN)
2222     ticket name length != 64
2223 #endif
2224     char tname[64];
2225     char tinst[64];
2226     char uname[PR_MAXNAMELEN];
2227     char tcell[MAXKTCREALMLEN];
2228     int fail = 0;
2229     int created = 0;
2230
2231     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2232     if (client && client->sid == rxr_CidOf(tcon) 
2233         && client->VenusEpoch == rxr_GetEpoch(tcon)
2234         && !(client->host->hostFlags & HOSTDELETED)) {
2235
2236         client->refCount++;
2237         h_Hold_r(client->host);
2238         if (!client->deleted && client->prfail != 2) {  
2239             /* Could add shared lock on client here */
2240             /* note that we don't have to lock entry in this path to
2241              * ensure CPS is initialized, since we don't call rx_SetSpecific
2242              * until initialization is done, and we only get here if
2243              * rx_GetSpecific located the client structure.
2244              */
2245             return client;
2246         }
2247         H_UNLOCK;
2248         ObtainWriteLock(&client->lock); /* released at end */
2249         H_LOCK;
2250     } else {
2251         client = NULL;
2252     }
2253
2254     authClass = rx_SecurityClassOf((struct rx_connection *)tcon);
2255     ViceLog(5,
2256             ("FindClient: authenticating connection: authClass=%d\n",
2257              authClass));
2258     if (authClass == 1) {
2259         /* A bcrypt tickets, no longer supported */
2260         ViceLog(1, ("FindClient: bcrypt ticket, using AnonymousID\n"));
2261         viceid = AnonymousID;
2262         expTime = 0x7fffffff;
2263     } else if (authClass == 2) {
2264         afs_int32 kvno;
2265     
2266         /* kerberos ticket */
2267         code = rxkad_GetServerInfo(tcon, /*level */ 0, (afs_uint32 *)&expTime,
2268                                    tname, tinst, tcell, &kvno);
2269         if (code) {
2270             ViceLog(1, ("Failed to get rxkad ticket info\n"));
2271             viceid = AnonymousID;
2272             expTime = 0x7fffffff;
2273         } else {
2274             int ilen = strlen(tinst);
2275             ViceLog(5,
2276                     ("FindClient: rxkad conn: name=%s,inst=%s,cell=%s,exp=%d,kvno=%d\n",
2277                      tname, tinst, tcell, expTime, kvno));
2278             strncpy(uname, tname, sizeof(uname));
2279             if (ilen) {
2280                 if (strlen(uname) + 1 + ilen >= sizeof(uname))
2281                     goto bad_name;
2282                 strcat(uname, ".");
2283                 strcat(uname, tinst);
2284             }
2285             /* translate the name to a vice id */
2286             code = MapName_r(uname, tcell, &viceid);
2287             if (code) {
2288               bad_name:
2289                 ViceLog(1,
2290                         ("failed to map name=%s, cell=%s -> code=%d\n", uname,
2291                          tcell, code));
2292                 fail = 1;
2293                 viceid = AnonymousID;
2294                 expTime = 0x7fffffff;
2295             }
2296         }
2297     } else {
2298         viceid = AnonymousID;   /* unknown security class */
2299         expTime = 0x7fffffff;
2300     }
2301
2302     if (!client) { /* loop */
2303         host = h_GetHost_r(tcon);       /* Returns with incremented refCount  */
2304
2305         if (!host) 
2306             return NULL;
2307
2308     retryfirstclient:
2309         /* First try to find the client structure */
2310         for (client = host->FirstClient; client; client = client->next) {
2311             if (!client->deleted && (client->sid == rxr_CidOf(tcon))
2312                 && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
2313                 client->refCount++;
2314                 H_UNLOCK;
2315                 ObtainWriteLock(&client->lock);
2316                 H_LOCK;
2317                 break;
2318             }
2319         }
2320
2321         /* Still no client structure - get one */
2322         if (!client) {
2323             h_Lock_r(host);
2324             if (host->hostFlags & HOSTDELETED) {
2325                 h_Unlock_r(host);
2326                 h_Release_r(host);
2327                 return NULL;
2328             }
2329             /* Retry to find the client structure */
2330             for (client = host->FirstClient; client; client = client->next) {
2331                 if (!client->deleted && (client->sid == rxr_CidOf(tcon))
2332                     && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
2333                     h_Unlock_r(host);
2334                     goto retryfirstclient;
2335                 }
2336             }
2337             created = 1;
2338             client = GetCE();
2339             ObtainWriteLock(&client->lock);
2340             client->refCount = 1;
2341             client->host = host;
2342 #if FS_STATS_DETAILED
2343             client->InSameNetwork = host->InSameNetwork;
2344 #endif /* FS_STATS_DETAILED */
2345             client->ViceId = viceid;
2346             client->expTime = expTime;  /* rx only */
2347             client->authClass = authClass;      /* rx only */
2348             client->sid = rxr_CidOf(tcon);
2349             client->VenusEpoch = rxr_GetEpoch(tcon);
2350             client->CPS.prlist_val = NULL;
2351             client->CPS.prlist_len = 0;
2352             h_Unlock_r(host);
2353         }
2354     }
2355     client->prfail = fail;
2356
2357     if (!(client->CPS.prlist_val) || (viceid != client->ViceId)) {
2358         client->CPS.prlist_len = 0;
2359         if (client->CPS.prlist_val && (client->ViceId != ANONYMOUSID))
2360             free(client->CPS.prlist_val);
2361         client->CPS.prlist_val = NULL;
2362         client->ViceId = viceid;
2363         client->expTime = expTime;
2364
2365         if (viceid == ANONYMOUSID) {
2366             client->CPS.prlist_len = AnonCPS.prlist_len;
2367             client->CPS.prlist_val = AnonCPS.prlist_val;
2368         } else {
2369             H_UNLOCK;
2370             code = hpr_GetCPS(viceid, &client->CPS);
2371             H_LOCK;
2372             if (code) {
2373                 char hoststr[16];
2374                 ViceLog(0,
2375                         ("pr_GetCPS failed(%d) for user %d, host %" AFS_PTR_FMT " (%s:%d)\n",
2376                          code, viceid, client->host, 
2377                          afs_inet_ntoa_r(client->host->host,hoststr),
2378                          ntohs(client->host->port)));
2379
2380                 /* Although ubik_Call (called by pr_GetCPS) traverses thru
2381                  * all protection servers and reevaluates things if no
2382                  * sync server or quorum is found we could still end up
2383                  * with one of these errors. In such case we would like to
2384                  * reevaluate the rpc call to find if there's cps for this
2385                  * guy. We treat other errors (except network failures
2386                  * ones - i.e. code < 0) as an indication that there is no
2387                  * CPS for this host.  Ideally we could like to deal this
2388                  * problem the other way around (i.e.  if code == NOCPS
2389                  * ignore else retry next time) but the problem is that
2390                  * there're other errors (i.e.  EPERM) for which we don't
2391                  * want to retry and we don't know the whole code list!
2392                  */
2393                 if (code < 0 || code == UNOQUORUM || code == UNOTSYNC)
2394                     client->prfail = 1;
2395             }
2396         }
2397         /* the disabling of system:administrators is so iffy and has so many
2398          * possible failure modes that we will disable it again */
2399         /* Turn off System:Administrator for safety  
2400          * if (AL_IsAMember(SystemId, client->CPS) == 0)
2401          * assert(AL_DisableGroup(SystemId, client->CPS) == 0); */
2402     }
2403
2404     /* Now, tcon may already be set to a rock, since we blocked with no host
2405      * or client locks set above in pr_GetCPS (XXXX some locking is probably
2406      * required).  So, before setting the RPC's rock, we should disconnect
2407      * the RPC from the other client structure's rock.
2408      */
2409     oldClient = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2410     if (oldClient && oldClient != client && oldClient->sid == rxr_CidOf(tcon)
2411         && oldClient->VenusEpoch == rxr_GetEpoch(tcon)) {
2412         char hoststr[16];
2413         if (!oldClient->deleted) {
2414             /* if we didn't create it, it's not ours to put back */
2415             if (created) {
2416                 ViceLog(0, ("FindClient: stillborn client %p(%x); "
2417                             "conn %p (host %s:%d) had client %p(%x)\n",
2418                             client, client->sid, tcon, 
2419                             afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2420                             ntohs(rxr_PortOf(tcon)),
2421                             oldClient, oldClient->sid));
2422                 if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
2423                     free(client->CPS.prlist_val);
2424                 client->CPS.prlist_val = NULL;
2425                 client->CPS.prlist_len = 0;
2426             }
2427             /* We should perhaps check for 0 here */
2428             client->refCount--;
2429             ReleaseWriteLock(&client->lock);
2430             if (created) {
2431                 FreeCE(client);
2432                 created = 0;
2433             } 
2434             oldClient->refCount++;
2435             H_UNLOCK;
2436             ObtainWriteLock(&oldClient->lock);
2437             H_LOCK;
2438             client = oldClient;
2439         } else {
2440             ViceLog(0, ("FindClient: deleted client %p(%x) already had "
2441                         "conn %p (host %s:%d), stolen by client %p(%x)\n",
2442                         oldClient, oldClient->sid, tcon, 
2443                         afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2444                         ntohs(rxr_PortOf(tcon)),
2445                         client, client->sid));
2446             /* rx_SetSpecific will be done immediately below */
2447         }
2448     }
2449     /* Avoid chaining in more than once. */
2450     if (created) {
2451         h_Lock_r(host);
2452
2453         if (host->hostFlags & HOSTDELETED) {
2454             h_Unlock_r(host);
2455             h_Release_r(host);
2456
2457             host = NULL;
2458             client->host = NULL;
2459
2460             if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val)
2461                 free(client->CPS.prlist_val);
2462             client->CPS.prlist_val = NULL;
2463             client->CPS.prlist_len = 0;
2464
2465             client->refCount--;
2466             ReleaseWriteLock(&client->lock);
2467             FreeCE(client);
2468             return NULL;
2469         }
2470
2471         client->next = host->FirstClient;
2472         host->FirstClient = client;
2473         h_Unlock_r(host);
2474         CurrentConnections++;   /* increment number of connections */
2475     }
2476     rx_SetSpecific(tcon, rxcon_client_key, client);
2477     ReleaseWriteLock(&client->lock);
2478
2479     return client;
2480
2481 }                               /*h_FindClient_r */
2482
2483 int
2484 h_ReleaseClient_r(struct client *client)
2485 {
2486     assert(client->refCount > 0);
2487     client->refCount--;
2488     return 0;
2489 }
2490
2491
2492 /*
2493  * Sigh:  this one is used to get the client AGAIN within the individual
2494  * server routines.  This does not bother h_Holding the host, since
2495  * this is assumed already have been done by the server main loop.
2496  * It does check tokens, since only the server routines can return the
2497  * VICETOKENDEAD error code
2498  */
2499 int
2500 GetClient(struct rx_connection *tcon, struct client **cp)
2501 {
2502     register struct client *client;
2503     char hoststr[16];
2504
2505     H_LOCK;
2506     *cp = NULL;
2507     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
2508     if (client == NULL) {
2509         ViceLog(0,
2510                 ("GetClient: no client in conn %p (host %s:%d), VBUSYING\n",
2511                  tcon, afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
2512                  ntohs(rxr_PortOf(tcon))));
2513         H_UNLOCK;
2514         return VBUSY;
2515     }
2516     if (rxr_CidOf(tcon) != client->sid || rxr_GetEpoch(tcon) != client->VenusEpoch) {
2517         ViceLog(0,
2518                 ("GetClient: tcon %p tcon sid %d client sid %d\n",
2519                  tcon, rxr_CidOf(tcon), client->sid));
2520         H_UNLOCK;
2521         return VBUSY;
2522     }
2523     if (client && client->LastCall > client->expTime && client->expTime) {
2524         ViceLog(1,
2525                 ("Token for %s at %s:%d expired %d\n", h_UserName(client),
2526                  afs_inet_ntoa_r(client->host->host, hoststr),
2527                  ntohs(client->host->port), client->expTime));
2528         H_UNLOCK;
2529         return VICETOKENDEAD;
2530     }
2531
2532     client->refCount++;
2533     *cp = client;
2534     H_UNLOCK;
2535     return 0;
2536 }                               /*GetClient */
2537
2538 int
2539 PutClient(struct client **cp)
2540 {
2541     if (*cp == NULL) 
2542         return -1;
2543
2544     H_LOCK;
2545     h_ReleaseClient_r(*cp);
2546     *cp = NULL;
2547     H_UNLOCK;
2548     return 0;
2549 }                               /*PutClient */
2550
2551
2552 /* Client user name for short term use.  Note that this is NOT inexpensive */
2553 char *
2554 h_UserName(struct client *client)
2555 {
2556     static char User[PR_MAXNAMELEN + 1];
2557     namelist lnames;
2558     idlist lids;
2559
2560     lids.idlist_len = 1;
2561     lids.idlist_val = (afs_int32 *) malloc(1 * sizeof(afs_int32));
2562     if (!lids.idlist_val) {
2563         ViceLog(0, ("Failed malloc in h_UserName\n"));
2564         assert(0);
2565     }
2566     lnames.namelist_len = 0;
2567     lnames.namelist_val = (prname *) 0;
2568     lids.idlist_val[0] = client->ViceId;
2569     if (hpr_IdToName(&lids, &lnames)) {
2570         /* We need to free id we alloced above! */
2571         free(lids.idlist_val);
2572         return "*UNKNOWN USER NAME*";
2573     }
2574     strncpy(User, lnames.namelist_val[0], PR_MAXNAMELEN);
2575     free(lids.idlist_val);
2576     free(lnames.namelist_val);
2577     return User;
2578 }                               /*h_UserName */
2579
2580
2581 void
2582 h_PrintStats(void)
2583 {
2584     ViceLog(0,
2585             ("Total Client entries = %d, blocks = %d; Host entries = %d, blocks = %d\n",
2586              CEs, CEBlocks, HTs, HTBlocks));
2587
2588 }                               /*h_PrintStats */
2589
2590
2591 static int
2592 h_PrintClient(register struct host *host, int flags, void *rock)
2593 {
2594     StreamHandle_t *file = (StreamHandle_t *)rock;
2595     register struct client *client;
2596     int i;
2597     char tmpStr[256];
2598     char tbuffer[32];
2599     char hoststr[16];
2600     time_t LastCall, expTime;
2601
2602     H_LOCK;
2603     LastCall = host->LastCall;
2604     if (host->hostFlags & HOSTDELETED) {
2605         H_UNLOCK;
2606         return flags;
2607     }
2608     (void)afs_snprintf(tmpStr, sizeof tmpStr,
2609                        "Host %s:%d down = %d, LastCall %s",
2610                        afs_inet_ntoa_r(host->host, hoststr),
2611                        ntohs(host->port), (host->hostFlags & VENUSDOWN),
2612                        afs_ctime(&LastCall, tbuffer,
2613                                  sizeof(tbuffer)));
2614     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2615     for (client = host->FirstClient; client; client = client->next) {
2616         if (!client->deleted) {
2617                 expTime = client->expTime;
2618                 (void)afs_snprintf(tmpStr, sizeof tmpStr,
2619                                    "    user id=%d,  name=%s, sl=%s till %s",
2620                                    client->ViceId, h_UserName(client),
2621                                    client->
2622                                    authClass ? "Authenticated" :
2623                                    "Not authenticated",
2624                                    client->
2625                                    authClass ? afs_ctime(&expTime, tbuffer,
2626                                                          sizeof(tbuffer))
2627                                    : "No Limit\n");
2628                 (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2629             (void)afs_snprintf(tmpStr, sizeof tmpStr, "      CPS-%d is [",
2630                                client->CPS.prlist_len);
2631             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2632             if (client->CPS.prlist_val) {
2633                 for (i = 0; i > client->CPS.prlist_len; i++) {
2634                     (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
2635                                        client->CPS.prlist_val[i]);
2636                     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2637                 }
2638             }
2639             sprintf(tmpStr, "]\n");
2640             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2641         }
2642     }
2643     H_UNLOCK;
2644     return flags;
2645
2646 }                               /*h_PrintClient */
2647
2648
2649
2650 /*
2651  * Print a list of clients, with last security level and token value seen,
2652  * if known
2653  */
2654 void
2655 h_PrintClients(void)
2656 {
2657     time_t now;
2658     char tmpStr[256];
2659     char tbuffer[32];
2660
2661     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_CLNTDUMP_FILEPATH, "w");
2662
2663     if (file == NULL) {
2664         ViceLog(0,
2665                 ("Couldn't create client dump file %s\n",
2666                  AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2667         return;
2668     }
2669     now = FT_ApproxTime();
2670     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active users at %s\n",
2671                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
2672     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2673     h_Enumerate(h_PrintClient, (char *)file);
2674     STREAM_REALLYCLOSE(file);
2675     ViceLog(0, ("Created client dump %s\n", AFSDIR_SERVER_CLNTDUMP_FILEPATH));
2676 }
2677
2678
2679
2680
2681 static int
2682 h_DumpHost(register struct host *host, int flags, void *rock)
2683 {
2684     StreamHandle_t *file = (StreamHandle_t *)rock;
2685     
2686     int i;
2687     char tmpStr[256];
2688     char hoststr[16];
2689
2690     H_LOCK;
2691     (void)afs_snprintf(tmpStr, sizeof tmpStr,
2692                        "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 [",
2693                        afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), host->index,
2694                        host->cblist, CheckLock(&host->lock), host->LastCall,
2695                        host->ActiveCall, (host->hostFlags & VENUSDOWN),
2696                        host->hostFlags & HOSTDELETED, host->Console,
2697                        host->hostFlags & CLIENTDELETED, host->hcpsfailed,
2698                        host->cpsCall);
2699     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2700     if (host->hcps.prlist_val)
2701         for (i = 0; i < host->hcps.prlist_len; i++) {
2702             (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
2703                                host->hcps.prlist_val[i]);
2704             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2705         }
2706     sprintf(tmpStr, "] [");
2707     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2708     if (host->interface)
2709         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
2710             char hoststr[16];
2711             sprintf(tmpStr, " %s:%d", 
2712                      afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2713                      ntohs(host->interface->interface[i].port));
2714             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2715         }
2716     sprintf(tmpStr, "] refCount:%d hostFlags:%hu\n", host->refCount, host->hostFlags);
2717     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2718
2719     H_UNLOCK;
2720     return flags;
2721
2722 }                               /*h_DumpHost */
2723
2724
2725 void
2726 h_DumpHosts(void)
2727 {
2728     time_t now;
2729     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_HOSTDUMP_FILEPATH, "w");
2730     char tmpStr[256];
2731     char tbuffer[32];
2732
2733     if (file == NULL) {
2734         ViceLog(0,
2735                 ("Couldn't create host dump file %s\n",
2736                  AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2737         return;
2738     }
2739     now = FT_ApproxTime();
2740     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active hosts at %s\n",
2741                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
2742     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2743     h_Enumerate(h_DumpHost, (char *)file);
2744     STREAM_REALLYCLOSE(file);
2745     ViceLog(0, ("Created host dump %s\n", AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2746
2747 }                               /*h_DumpHosts */
2748
2749 #ifdef AFS_DEMAND_ATTACH_FS
2750 /*
2751  * demand attach fs
2752  * host state serialization
2753  */
2754 static int h_stateFillHeader(struct host_state_header * hdr);
2755 static int h_stateCheckHeader(struct host_state_header * hdr);
2756 static int h_stateAllocMap(struct fs_dump_state * state);
2757 static int h_stateSaveHost(struct host * host, int flags, void *rock);
2758 static int h_stateRestoreHost(struct fs_dump_state * state);
2759 static int h_stateRestoreIndex(struct host * h, int flags, void *rock);
2760 static int h_stateVerifyHost(struct host * h, int flags, void *rock);
2761 static int h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port);
2762 static int h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h);
2763 static void h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out);
2764 static void h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out);
2765
2766
2767 /* this procedure saves all host state to disk for fast startup */
2768 int
2769 h_stateSave(struct fs_dump_state * state)
2770 {
2771     AssignInt64(state->eof_offset, &state->hdr->h_offset);
2772
2773     /* XXX debug */
2774     ViceLog(0, ("h_stateSave:  hostCount=%d\n", hostCount));
2775
2776     /* invalidate host state header */
2777     memset(state->h_hdr, 0, sizeof(struct host_state_header));
2778
2779     if (fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2780                             sizeof(struct host_state_header))) {
2781         state->bail = 1;
2782         goto done;
2783     }
2784
2785     fs_stateIncEOF(state, sizeof(struct host_state_header));
2786
2787     h_Enumerate_r(h_stateSaveHost, hostList, (char *)state);
2788     if (state->bail) {
2789         goto done;
2790     }
2791
2792     h_stateFillHeader(state->h_hdr);
2793
2794     /* write the real header to disk */
2795     state->bail = fs_stateWriteHeader(state, &state->hdr->h_offset, state->h_hdr,
2796                                       sizeof(struct host_state_header));
2797
2798  done:
2799     return state->bail;
2800 }
2801
2802 /* demand attach fs
2803  * host state serialization
2804  *
2805  * this procedure restores all host state from a disk for fast startup 
2806  */
2807 int
2808 h_stateRestore(struct fs_dump_state * state)
2809 {
2810     int i, records;
2811
2812     /* seek to the right position and read in the host state header */
2813     if (fs_stateReadHeader(state, &state->hdr->h_offset, state->h_hdr,
2814                            sizeof(struct host_state_header))) {
2815         state->bail = 1;
2816         goto done;
2817     }
2818
2819     /* check the validity of the header */
2820     if (h_stateCheckHeader(state->h_hdr)) {
2821         state->bail = 1;
2822         goto done;
2823     }
2824
2825     records = state->h_hdr->records;
2826
2827     if (h_stateAllocMap(state)) {
2828         state->bail = 1;
2829         goto done;
2830     }
2831
2832     /* iterate over records restoring host state */
2833     for (i=0; i < records; i++) {
2834         if (h_stateRestoreHost(state) != 0) {
2835             state->bail = 1;
2836             break;
2837         }
2838     }
2839
2840  done:
2841     return state->bail;
2842 }
2843
2844 int
2845 h_stateRestoreIndices(struct fs_dump_state * state)
2846 {
2847     h_Enumerate_r(h_stateRestoreIndex, hostList, (char *)state);
2848     return state->bail;
2849 }
2850
2851 static int
2852 h_stateRestoreIndex(struct host * h, int flags, void *rock)
2853 {
2854     struct fs_dump_state *state = (struct fs_dump_state *)rock;
2855     if (cb_OldToNew(state, h->cblist, &h->cblist)) {
2856         return H_ENUMERATE_BAIL(flags);
2857     }
2858     return flags;
2859 }
2860
2861 int
2862 h_stateVerify(struct fs_dump_state * state)
2863 {
2864     h_Enumerate_r(h_stateVerifyHost, hostList, (char *)state);
2865     return state->bail;
2866 }
2867
2868 static int
2869 h_stateVerifyHost(struct host * h, int flags, void* rock)
2870 {
2871     struct fs_dump_state *state = (struct fs_dump_state *)rock;
2872     int i;
2873
2874     if (h == NULL) {
2875         ViceLog(0, ("h_stateVerifyHost: error: NULL host pointer in linked list\n"));
2876         return H_ENUMERATE_BAIL(flags);
2877     }
2878
2879     if (h->interface) {
2880         for (i = h->interface->numberOfInterfaces-1; i >= 0; i--) {
2881             if (h_stateVerifyAddrHash(state, h, h->interface->interface[i].addr, 
2882                                       h->interface->interface[i].port)) {
2883                 state->bail = 1;
2884             }
2885         }
2886         if (h_stateVerifyUuidHash(state, h)) {
2887             state->bail = 1;
2888         }
2889     } else if (h_stateVerifyAddrHash(state, h, h->host, h->port)) {
2890         state->bail = 1;
2891     }
2892
2893     if (cb_stateVerifyHCBList(state, h)) {
2894         state->bail = 1;
2895     }
2896
2897     return flags;
2898 }
2899
2900 static int
2901 h_stateVerifyAddrHash(struct fs_dump_state * state, struct host * h, afs_uint32 addr, afs_uint16 port)
2902 {
2903     int ret = 0, found = 0;
2904     struct host *host = NULL;
2905     struct h_AddrHashChain *chain;
2906     int index = h_HashIndex(addr);
2907     char tmp[16];
2908     int chain_len = 0;
2909
2910     for (chain = hostAddrHashTable[index]; chain; chain = chain->next) {
2911         host = chain->hostPtr;
2912         if (host == NULL) {
2913             afs_inet_ntoa_r(addr, tmp);
2914             ViceLog(0, ("h_stateVerifyAddrHash: error: addr hash chain has NULL host ptr (lookup addr %s)\n", tmp));
2915             ret = 1;
2916             goto done;
2917         }
2918         if ((chain->addr == addr) && (chain->port == port)) {
2919             if (host != h) {
2920                 ViceLog(0, ("h_stateVerifyAddrHash: warning: addr hash entry points to different host struct (%d, %d)\n", 
2921                             h->index, host->index));
2922                 state->flags.warnings_generated = 1;
2923             }
2924             found = 1;
2925             break;
2926         }
2927         if (chain_len > FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN) {
2928             ViceLog(0, ("h_stateVerifyAddrHash: error: hash chain length exceeds %d; assuming there's a loop\n",
2929                         FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN));
2930             ret = 1;
2931             goto done;
2932         }
2933         chain_len++;
2934     }
2935
2936     if (!found) {
2937         afs_inet_ntoa_r(addr, tmp);
2938         if (state->mode == FS_STATE_LOAD_MODE) {
2939             ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s not found in hash\n", tmp));
2940             ret = 1;
2941             goto done;
2942         } else {
2943             ViceLog(0, ("h_stateVerifyAddrHash: warning: addr %s not found in hash\n", tmp));
2944             state->flags.warnings_generated = 1;
2945         }
2946     }
2947
2948  done:
2949     return ret;
2950 }
2951
2952 static int
2953 h_stateVerifyUuidHash(struct fs_dump_state * state, struct host * h)
2954 {
2955     int ret = 0, found = 0;
2956     struct host *host = NULL;
2957     struct h_UuidHashChain *chain;
2958     afsUUID * uuidp = &h->interface->uuid;
2959     int index = h_UuidHashIndex(uuidp);
2960     char tmp[40];
2961     int chain_len = 0;
2962
2963     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
2964         host = chain->hostPtr;
2965         if (host == NULL) {
2966             afsUUID_to_string(uuidp, tmp, sizeof(tmp));
2967             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid hash chain has NULL host ptr (lookup uuid %s)\n", tmp));
2968             ret = 1;
2969             goto done;
2970         }
2971         if (host->interface &&
2972             afs_uuid_equal(&host->interface->uuid, uuidp)) {
2973             if (host != h) {
2974                 ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid hash entry points to different host struct (%d, %d)\n", 
2975                             h->index, host->index));
2976                 state->flags.warnings_generated = 1;
2977             }
2978             found = 1;
2979             goto done;
2980         }
2981         if (chain_len > FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN) {
2982             ViceLog(0, ("h_stateVerifyUuidHash: error: hash chain length exceeds %d; assuming there's a loop\n",
2983                         FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN));
2984             ret = 1;
2985             goto done;
2986         }
2987         chain_len++;
2988     }
2989
2990     if (!found) {
2991         afsUUID_to_string(uuidp, tmp, sizeof(tmp));
2992         if (state->mode == FS_STATE_LOAD_MODE) {
2993             ViceLog(0, ("h_stateVerifyUuidHash: error: uuid %s not found in hash\n", tmp));
2994             ret = 1;
2995             goto done;
2996         } else {
2997             ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid %s not found in hash\n", tmp));
2998             state->flags.warnings_generated = 1;
2999         }
3000     }
3001
3002  done:
3003     return ret;
3004 }
3005
3006 /* create the host state header structure */
3007 static int
3008 h_stateFillHeader(struct host_state_header * hdr)
3009 {
3010     hdr->stamp.magic = HOST_STATE_MAGIC;
3011     hdr->stamp.version = HOST_STATE_VERSION;
3012     return 0;
3013 }
3014
3015 /* check the contents of the host state header structure */
3016 static int
3017 h_stateCheckHeader(struct host_state_header * hdr)
3018 {
3019     int ret=0;
3020
3021     if (hdr->stamp.magic != HOST_STATE_MAGIC) {
3022         ViceLog(0, ("check_host_state_header: invalid state header\n"));
3023         ret = 1;
3024     }
3025     else if (hdr->stamp.version != HOST_STATE_VERSION) {
3026         ViceLog(0, ("check_host_state_header: unknown version number\n"));
3027         ret = 1;
3028     }
3029     return ret;
3030 }
3031
3032 /* allocate the host id mapping table */
3033 static int
3034 h_stateAllocMap(struct fs_dump_state * state)
3035 {
3036     state->h_map.len = state->h_hdr->index_max + 1;
3037     state->h_map.entries = (struct idx_map_entry_t *)
3038         calloc(state->h_map.len, sizeof(struct idx_map_entry_t));
3039     return (state->h_map.entries != NULL) ? 0 : 1;
3040 }
3041
3042 /* function called by h_Enumerate to save a host to disk */
3043 static int
3044 h_stateSaveHost(struct host * host, int flags, void* rock)
3045 {
3046     struct fs_dump_state *state = (struct fs_dump_state *) rock;
3047     int if_len=0, hcps_len=0;
3048     struct hostDiskEntry hdsk;
3049     struct host_state_entry_header hdr;
3050     struct Interface * ifp = NULL;
3051     afs_int32 * hcps = NULL;
3052     struct iovec iov[4];
3053     int iovcnt = 2;
3054
3055     memset(&hdr, 0, sizeof(hdr));
3056
3057     if (state->h_hdr->index_max < host->index) {
3058         state->h_hdr->index_max = host->index;
3059     }
3060
3061     h_hostToDiskEntry_r(host, &hdsk);
3062     if (host->interface) {
3063         if_len = sizeof(struct Interface) + 
3064             ((host->interface->numberOfInterfaces-1) * sizeof(struct AddrPort));
3065         ifp = (struct Interface *) malloc(if_len);
3066         assert(ifp != NULL);
3067         memcpy(ifp, host->interface, if_len);
3068         hdr.interfaces = host->interface->numberOfInterfaces;
3069         iov[iovcnt].iov_base = (char *) ifp;
3070         iov[iovcnt].iov_len = if_len;
3071         iovcnt++;
3072     }
3073     if (host->hcps.prlist_val) {
3074         hdr.hcps = host->hcps.prlist_len;
3075         hcps_len = hdr.hcps * sizeof(afs_int32);
3076         hcps = (afs_int32 *) malloc(hcps_len);
3077         assert(hcps != NULL);
3078         memcpy(hcps, host->hcps.prlist_val, hcps_len);
3079         iov[iovcnt].iov_base = (char *) hcps;
3080         iov[iovcnt].iov_len = hcps_len;
3081         iovcnt++;
3082     }
3083
3084     if (hdsk.index > state->h_hdr->index_max)
3085         state->h_hdr->index_max = hdsk.index;
3086
3087     hdr.len = sizeof(struct host_state_entry_header) + 
3088         sizeof(struct hostDiskEntry) + if_len + hcps_len;
3089     hdr.magic = HOST_STATE_ENTRY_MAGIC;
3090
3091     iov[0].iov_base = (char *) &hdr;
3092     iov[0].iov_len = sizeof(hdr);
3093     iov[1].iov_base = (char *) &hdsk;
3094     iov[1].iov_len = sizeof(struct hostDiskEntry);
3095     
3096     if (fs_stateWriteV(state, iov, iovcnt)) {
3097         ViceLog(0, ("h_stateSaveHost: failed to save host %d", host->index));
3098         state->bail = 1;
3099     }
3100
3101     fs_stateIncEOF(state, hdr.len);
3102
3103     state->h_hdr->records++;
3104
3105     if (ifp)
3106         free(ifp);
3107     if (hcps)
3108         free(hcps);
3109     if (state->bail) {
3110         return H_ENUMERATE_BAIL(flags);
3111     }
3112     return flags;
3113 }
3114
3115 /* restores a host from disk */
3116 static int
3117 h_stateRestoreHost(struct fs_dump_state * state)
3118 {
3119     int ifp_len=0, hcps_len=0, bail=0;
3120     struct host_state_entry_header hdr;
3121     struct hostDiskEntry hdsk;
3122     struct host *host = NULL;
3123     struct Interface *ifp = NULL;
3124     afs_int32 * hcps = NULL;
3125     struct iovec iov[3];
3126     int iovcnt = 1;
3127
3128     if (fs_stateRead(state, &hdr, sizeof(hdr))) {
3129         ViceLog(0, ("h_stateRestoreHost: failed to read host entry header from dump file '%s'\n",
3130                     state->fn));
3131         bail = 1;
3132         goto done;
3133     }
3134
3135     if (hdr.magic != HOST_STATE_ENTRY_MAGIC) {
3136         ViceLog(0, ("h_stateRestoreHost: fileserver state dump file '%s' is corrupt.\n",
3137                     state->fn));
3138         bail = 1;
3139         goto done;
3140     }
3141
3142     iov[0].iov_base = (char *) &hdsk;
3143     iov[0].iov_len = sizeof(struct hostDiskEntry);
3144
3145     if (hdr.interfaces) {
3146         ifp_len = sizeof(struct Interface) +
3147             ((hdr.interfaces-1) * sizeof(struct AddrPort));
3148         ifp = (struct Interface *) malloc(ifp_len);
3149         assert(ifp != NULL);
3150         iov[iovcnt].iov_base = (char *) ifp;
3151         iov[iovcnt].iov_len = ifp_len;
3152         iovcnt++;
3153     }
3154     if (hdr.hcps) {
3155         hcps_len = hdr.hcps * sizeof(afs_int32);
3156         hcps = (afs_int32 *) malloc(hcps_len);
3157         assert(hcps != NULL);
3158         iov[iovcnt].iov_base = (char *) hcps;
3159         iov[iovcnt].iov_len = hcps_len;
3160         iovcnt++;
3161     }
3162
3163     if ((ifp_len + hcps_len + sizeof(hdsk) + sizeof(hdr)) != hdr.len) {
3164         ViceLog(0, ("h_stateRestoreHost: host entry header length fields are inconsistent\n"));
3165         bail = 1;
3166         goto done;
3167     }
3168
3169     if (fs_stateReadV(state, iov, iovcnt)) {
3170         ViceLog(0, ("h_stateRestoreHost: failed to read host entry\n"));
3171         bail = 1;
3172         goto done;
3173     }
3174
3175     if (!hdr.hcps && hdsk.hcps_valid) {
3176         /* valid, zero-length host cps ; does this ever happen? */
3177         hcps = (afs_int32 *) malloc(sizeof(afs_int32));
3178         assert(hcps != NULL);
3179     }
3180
3181     host = GetHT();
3182     assert(host != NULL);
3183
3184     if (ifp) {
3185         host->interface = ifp;
3186     }
3187     if (hcps) {
3188         host->hcps.prlist_val = hcps;
3189         host->hcps.prlist_len = hdr.hcps;
3190     }
3191
3192     h_diskEntryToHost_r(&hdsk, host);
3193     h_SetupCallbackConn_r(host);
3194
3195     h_AddHostToAddrHashTable_r(host->host, host->port, host);
3196     if (ifp) {
3197         int i;
3198         for (i = ifp->numberOfInterfaces-1; i >= 0; i--) {
3199             if (ifp->interface[i].valid && 
3200                 !(ifp->interface[i].addr == host->host &&
3201                   ifp->interface[i].port == host->port)) {
3202                 h_AddHostToAddrHashTable_r(ifp->interface[i].addr, 
3203                                            ifp->interface[i].port, 
3204                                            host);
3205             }
3206         }
3207         h_AddHostToUuidHashTable_r(&ifp->uuid, host);
3208     }
3209     h_InsertList_r(host);
3210
3211     /* setup host id map entry */
3212     state->h_map.entries[hdsk.index].old_idx = hdsk.index;
3213     state->h_map.entries[hdsk.index].new_idx = host->index;
3214
3215  done:
3216     if (bail) {
3217         if (ifp)
3218             free(ifp);
3219         if (hcps)
3220             free(hcps);
3221     }
3222     return bail;
3223 }
3224
3225 /* serialize a host structure to disk */
3226 static void
3227 h_hostToDiskEntry_r(struct host * in, struct hostDiskEntry * out)
3228 {
3229     out->host = in->host;
3230     out->port = in->port;
3231     out->hostFlags = in->hostFlags;
3232     out->Console = in->Console;
3233     out->hcpsfailed = in->hcpsfailed;
3234     out->LastCall = in->LastCall;
3235     out->ActiveCall = in->ActiveCall;
3236     out->cpsCall = in->cpsCall;
3237     out->cblist = in->cblist;
3238 #ifdef FS_STATS_DETAILED
3239     out->InSameNetwork = in->InSameNetwork;
3240 #endif
3241
3242     /* special fields we save, but are not memcpy'd back on restore */
3243     out->index = in->index;
3244     out->hcps_len = in->hcps.prlist_len;
3245     out->hcps_valid = (in->hcps.prlist_val == NULL) ? 0 : 1;
3246 }
3247
3248 /* restore a host structure from disk */
3249 static void
3250 h_diskEntryToHost_r(struct hostDiskEntry * in, struct host * out)
3251 {
3252     out->host = in->host;
3253     out->port = in->port;
3254     out->hostFlags = in->hostFlags;
3255     out->Console = in->Console;
3256     out->hcpsfailed = in->hcpsfailed;
3257     out->LastCall = in->LastCall;
3258     out->ActiveCall = in->ActiveCall;
3259     out->cpsCall = in->cpsCall;
3260     out->cblist = in->cblist;
3261 #ifdef FS_STATS_DETAILED
3262     out->InSameNetwork = in->InSameNetwork;
3263 #endif
3264 }
3265
3266 /* index translation routines */
3267 int
3268 h_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
3269 {
3270     int ret = 0;
3271
3272     /* hosts use a zero-based index, so old==0 is valid */
3273
3274     if (old >= state->h_map.len) {
3275         ViceLog(0, ("h_OldToNew: index %d is out of range\n", old));
3276         ret = 1;
3277     } else if (state->h_map.entries[old].old_idx != old) { /* sanity check */
3278         ViceLog(0, ("h_OldToNew: index %d points to an invalid host record\n", old));
3279         ret = 1;
3280     } else {
3281         *new = state->h_map.entries[old].new_idx;
3282     }
3283
3284     return ret;
3285 }
3286 #endif /* AFS_DEMAND_ATTACH_FS */
3287
3288
3289 /*
3290  * This counts the number of workstations, the number of active workstations,
3291  * and the number of workstations declared "down" (i.e. not heard from
3292  * recently).  An active workstation has received a call since the cutoff
3293  * time argument passed.
3294  */
3295 void
3296 h_GetWorkStats(int *nump, int *activep, int *delp, afs_int32 cutofftime)
3297 {
3298     register struct host *host;
3299     register int num = 0, active = 0, del = 0;
3300     int count;
3301
3302     H_LOCK;
3303     for (count = 0, host = hostList; host && count < hostCount; host = host->next, count++) {
3304         if (!(host->hostFlags & HOSTDELETED)) {
3305             num++;
3306             if (host->ActiveCall > cutofftime)
3307                 active++;
3308             if (host->hostFlags & VENUSDOWN)
3309                 del++;
3310         }
3311     }
3312     if (count != hostCount) {
3313         ViceLog(0, ("h_GetWorkStats found %d of %d hosts\n", count, hostCount));
3314     } else if (host != NULL) {
3315         ViceLog(0, ("h_GetWorkStats found more than %d hosts\n", hostCount));
3316         ShutDownAndCore(PANIC);
3317     }
3318     H_UNLOCK;
3319     if (nump)
3320         *nump = num;
3321     if (activep)
3322         *activep = active;
3323     if (delp)
3324         *delp = del;
3325
3326 }                               /*h_GetWorkStats */
3327
3328
3329 /*------------------------------------------------------------------------
3330  * PRIVATE h_ClassifyAddress
3331  *
3332  * Description:
3333  *      Given a target IP address and a candidate IP address (both
3334  *      in host byte order), classify the candidate into one of three
3335  *      buckets in relation to the target by bumping the counters passed
3336  *      in as parameters.
3337  *
3338  * Arguments:
3339  *      a_targetAddr       : Target address.
3340  *      a_candAddr         : Candidate address.
3341  *      a_sameNetOrSubnetP : Ptr to counter to bump when the two
3342  *                           addresses are either in the same network
3343  *                           or the same subnet.
3344  *      a_diffSubnetP      : ...when the candidate is in a different
3345  *                           subnet.
3346  *      a_diffNetworkP     : ...when the candidate is in a different
3347  *                           network.
3348  *
3349  * Returns:
3350  *      Nothing.
3351  *
3352  * Environment:
3353  *      The target and candidate addresses are both in host byte
3354  *      order, NOT network byte order, when passed in.
3355  *
3356  * Side Effects:
3357  *      As advertised.
3358  *------------------------------------------------------------------------*/
3359
3360 static void
3361 h_ClassifyAddress(afs_uint32 a_targetAddr, afs_uint32 a_candAddr,
3362                   afs_int32 * a_sameNetOrSubnetP, afs_int32 * a_diffSubnetP,
3363                   afs_int32 * a_diffNetworkP)
3364 {                               /*h_ClassifyAddress */
3365
3366     afs_uint32 targetNet;
3367     afs_uint32 targetSubnet;
3368     afs_uint32 candNet;
3369     afs_uint32 candSubnet;
3370
3371     /*
3372      * Put bad values into the subnet info to start with.
3373      */
3374     targetSubnet = (afs_uint32) 0;
3375     candSubnet = (afs_uint32) 0;
3376
3377     /*
3378      * Pull out the network and subnetwork numbers from the target
3379      * and candidate addresses.  We can short-circuit this whole
3380      * affair if the target and candidate addresses are not of the
3381      * same class.
3382      */
3383     if (IN_CLASSA(a_targetAddr)) {
3384         if (!(IN_CLASSA(a_candAddr))) {
3385             (*a_diffNetworkP)++;
3386             return;
3387         }
3388         targetNet = a_targetAddr & IN_CLASSA_NET;
3389         candNet = a_candAddr & IN_CLASSA_NET;
3390         if (IN_SUBNETA(a_targetAddr))
3391             targetSubnet = a_targetAddr & IN_CLASSA_SUBNET;
3392         if (IN_SUBNETA(a_candAddr))
3393             candSubnet = a_candAddr & IN_CLASSA_SUBNET;
3394     } else if (IN_CLASSB(a_targetAddr)) {
3395         if (!(IN_CLASSB(a_candAddr))) {
3396             (*a_diffNetworkP)++;
3397             return;
3398         }
3399         targetNet = a_targetAddr & IN_CLASSB_NET;
3400         candNet = a_candAddr & IN_CLASSB_NET;
3401         if (IN_SUBNETB(a_targetAddr))
3402             targetSubnet = a_targetAddr & IN_CLASSB_SUBNET;
3403         if (IN_SUBNETB(a_candAddr))
3404             candSubnet = a_candAddr & IN_CLASSB_SUBNET;
3405     } /*Class B target */
3406     else if (IN_CLASSC(a_targetAddr)) {
3407         if (!(IN_CLASSC(a_candAddr))) {
3408             (*a_diffNetworkP)++;
3409             return;
3410         }
3411         targetNet = a_targetAddr & IN_CLASSC_NET;
3412         candNet = a_candAddr & IN_CLASSC_NET;
3413
3414         /*
3415          * Note that class C addresses can't have subnets,
3416          * so we leave the defaults untouched.
3417          */
3418     } /*Class C target */
3419     else {
3420         targetNet = a_targetAddr;
3421         candNet = a_candAddr;
3422     }                           /*Class D address */
3423
3424     /*
3425      * Now, simply compare the extracted net and subnet values for
3426      * the two addresses (which at this point are known to be of the
3427      * same class)
3428      */
3429     if (targetNet == candNet) {
3430         if (targetSubnet == candSubnet)
3431             (*a_sameNetOrSubnetP)++;
3432         else
3433             (*a_diffSubnetP)++;
3434     } else
3435         (*a_diffNetworkP)++;
3436
3437 }                               /*h_ClassifyAddress */
3438
3439
3440 /*------------------------------------------------------------------------
3441  * EXPORTED h_GetHostNetStats
3442  *
3443  * Description:
3444  *      Iterate through the host table, and classify each (non-deleted)
3445  *      host entry into ``proximity'' categories (same net or subnet,
3446  *      different subnet, different network).
3447  *
3448  * Arguments:
3449  *      a_numHostsP        : Set to total number of (non-deleted) hosts.
3450  *      a_sameNetOrSubnetP : Set to # hosts on same net/subnet as server.
3451  *      a_diffSubnetP      : Set to # hosts on diff subnet as server.
3452  *      a_diffNetworkP     : Set to # hosts on diff network as server.
3453  *
3454  * Returns:
3455  *      Nothing.
3456  *
3457  * Environment:
3458  *      We only count non-deleted hosts.  The storage pointed to by our
3459  *      parameters is zeroed upon entry.
3460  *
3461  * Side Effects:
3462  *      As advertised.
3463  *------------------------------------------------------------------------*/
3464
3465 void
3466 h_GetHostNetStats(afs_int32 * a_numHostsP, afs_int32 * a_sameNetOrSubnetP,
3467                   afs_int32 * a_diffSubnetP, afs_int32 * a_diffNetworkP)
3468 {                               /*h_GetHostNetStats */
3469
3470     register struct host *hostP;        /*Ptr to current host entry */
3471     register afs_uint32 currAddr_HBO;   /*Curr host addr, host byte order */
3472     int count;
3473
3474     /*
3475      * Clear out the storage pointed to by our parameters.
3476      */
3477     *a_numHostsP = (afs_int32) 0;
3478     *a_sameNetOrSubnetP = (afs_int32) 0;
3479     *a_diffSubnetP = (afs_int32) 0;
3480     *a_diffNetworkP = (afs_int32) 0;
3481
3482     H_LOCK;
3483     for (count = 0, hostP = hostList; hostP && count < hostCount; hostP = hostP->next, count++) {
3484         if (!(hostP->hostFlags & HOSTDELETED)) {
3485             /*
3486              * Bump the number of undeleted host entries found.
3487              * In classifying the current entry's address, make
3488              * sure to first convert to host byte order.
3489              */
3490             (*a_numHostsP)++;
3491             currAddr_HBO = (afs_uint32) ntohl(hostP->host);
3492             h_ClassifyAddress(FS_HostAddr_HBO, currAddr_HBO,
3493                               a_sameNetOrSubnetP, a_diffSubnetP,
3494                               a_diffNetworkP);
3495         }                       /*Only look at non-deleted hosts */
3496     }                           /*For each host record hashed to this index */
3497     if (count != hostCount) {
3498         ViceLog(0, ("h_GetHostNetStats found %d of %d hosts\n", count, hostCount));
3499     } else if (hostP != NULL) {
3500         ViceLog(0, ("h_GetHostNetStats found more than %d hosts\n", hostCount));
3501         ShutDownAndCore(PANIC);
3502     }
3503     H_UNLOCK;
3504 }                               /*h_GetHostNetStats */
3505
3506 static afs_uint32 checktime;
3507 static afs_uint32 clientdeletetime;
3508 static struct AFSFid zerofid;
3509
3510
3511 /*
3512  * XXXX: This routine could use Multi-Rx to avoid serializing the timeouts.
3513  * Since it can serialize them, and pile up, it should be a separate LWP
3514  * from other events.
3515  */
3516 #if 0
3517 static int
3518 CheckHost(register struct host *host, int flags, void *rock)
3519 {
3520     register struct client *client;
3521     struct rx_connection *cb_conn = NULL;
3522     int code;
3523
3524 #ifdef AFS_DEMAND_ATTACH_FS
3525     /* kill the checkhost lwp ASAP during shutdown */
3526     FS_STATE_RDLOCK;
3527     if (fs_state.mode == FS_MODE_SHUTDOWN) {
3528         FS_STATE_UNLOCK;
3529         return H_ENUMERATE_BAIL(flags);
3530     }
3531     FS_STATE_UNLOCK;
3532 #endif
3533
3534     /* Host is held by h_Enumerate */
3535     H_LOCK;
3536     for (client = host->FirstClient; client; client = client->next) {
3537         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
3538             client->deleted = 1;
3539             host->hostFlags |= CLIENTDELETED;
3540         }
3541     }
3542     if (host->LastCall < checktime) {
3543         h_Lock_r(host);
3544         if (!(host->hostFlags & HOSTDELETED)) {
3545             host->hostFlags |= HWHO_INPROGRESS;
3546             cb_conn = host->callback_rxcon;
3547             rx_GetConnection(cb_conn);
3548             if (host->LastCall < clientdeletetime) {
3549                 host->hostFlags |= HOSTDELETED;
3550                 if (!(host->hostFlags & VENUSDOWN)) {
3551                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
3552                     if (host->interface) {
3553                         H_UNLOCK;
3554                         code =
3555                             RXAFSCB_InitCallBackState3(cb_conn,
3556                                                        &FS_HostUUID);
3557                         H_LOCK;
3558                     } else {
3559                         H_UNLOCK;
3560                         code =
3561                             RXAFSCB_InitCallBackState(cb_conn);
3562                         H_LOCK;
3563                     }
3564                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
3565                     if (code) {
3566                         char hoststr[16];
3567                         (void)afs_inet_ntoa_r(host->host, hoststr);
3568                         ViceLog(0,
3569                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
3570                                  hoststr, ntohs(host->port)));
3571                         host->hostFlags |= VENUSDOWN;
3572                     }
3573                     /* Note:  it's safe to delete hosts even if they have call
3574                      * back state, because break delayed callbacks (called when a
3575                      * message is received from the workstation) will always send a 
3576                      * break all call backs to the workstation if there is no
3577                      * callback.
3578                      */
3579                 }
3580             } else {
3581                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
3582                     char hoststr[16];
3583                     (void)afs_inet_ntoa_r(host->host, hoststr);
3584                     if (host->interface) {
3585                         afsUUID uuid = host->interface->uuid;
3586                         H_UNLOCK;
3587                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
3588                         H_LOCK;
3589                         if (code) {
3590                             if (MultiProbeAlternateAddress_r(host)) {
3591                                 ViceLog(0,("CheckHost: Probing all interfaces of host %s:%d failed, code %d\n",
3592                                             hoststr, ntohs(host->port), code));
3593                                 host->hostFlags |= VENUSDOWN;
3594                             }
3595                         }
3596                     } else {
3597                         H_UNLOCK;
3598                         code = RXAFSCB_Probe(cb_conn);
3599                         H_LOCK;
3600                         if (code) {
3601                             ViceLog(0,
3602                                     ("CheckHost: Probe failed for host %s:%d, code %d\n", 
3603                                      hoststr, ntohs(host->port), code));
3604                             host->hostFlags |= VENUSDOWN;
3605                         }
3606                     }
3607                 }
3608             }
3609             H_UNLOCK;
3610             rx_PutConnection(cb_conn);
3611             cb_conn=NULL;
3612             H_LOCK;
3613             host->hostFlags &= ~HWHO_INPROGRESS;
3614         }
3615         h_Unlock_r(host);
3616     }
3617     H_UNLOCK;
3618     return held;
3619
3620 }                               /*CheckHost */
3621 #endif
3622
3623 int
3624 CheckHost_r(register struct host *host, int flags, void *dummy)
3625 {
3626     register struct client *client;
3627     struct rx_connection *cb_conn = NULL;
3628     int code;
3629
3630 #ifdef AFS_DEMAND_ATTACH_FS
3631     /* kill the checkhost lwp ASAP during shutdown */
3632     FS_STATE_RDLOCK;
3633     if (fs_state.mode == FS_MODE_SHUTDOWN) {
3634         FS_STATE_UNLOCK;
3635         return H_ENUMERATE_BAIL(flags);
3636     }
3637     FS_STATE_UNLOCK;
3638 #endif
3639
3640     /* Host is held by h_Enumerate_r */
3641     for (client = host->FirstClient; client; client = client->next) {
3642         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
3643             client->deleted = 1;
3644             host->hostFlags |= CLIENTDELETED;
3645         }
3646     }
3647     if (host->LastCall < checktime) {
3648         h_Lock_r(host);
3649         if (!(host->hostFlags & HOSTDELETED)) {
3650             cb_conn = host->callback_rxcon;
3651             rx_GetConnection(cb_conn);
3652             if (host->LastCall < clientdeletetime) {
3653                 host->hostFlags |= HOSTDELETED;
3654                 if (!(host->hostFlags & VENUSDOWN)) {
3655                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
3656                     if (host->interface) {
3657                         H_UNLOCK;
3658                         code =
3659                             RXAFSCB_InitCallBackState3(cb_conn,
3660                                                        &FS_HostUUID);
3661                         H_LOCK;
3662                     } else {
3663                         H_UNLOCK;
3664                         code =
3665                             RXAFSCB_InitCallBackState(cb_conn);
3666                         H_LOCK;
3667                     }
3668                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
3669                     if (code) {
3670                         char hoststr[16];
3671                         (void)afs_inet_ntoa_r(host->host, hoststr);
3672                         ViceLog(0,
3673                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
3674                                  hoststr, ntohs(host->port)));
3675                         host->hostFlags |= VENUSDOWN;
3676                     }
3677                     /* Note:  it's safe to delete hosts even if they have call
3678                      * back state, because break delayed callbacks (called when a
3679                      * message is received from the workstation) will always send a 
3680                      * break all call backs to the workstation if there is no
3681                      * callback.
3682                      */
3683                 }
3684             } else {
3685                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
3686                     char hoststr[16];
3687                     (void)afs_inet_ntoa_r(host->host, hoststr);
3688                     if (host->interface) {
3689                         afsUUID uuid = host->interface->uuid;
3690                         H_UNLOCK;
3691                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
3692                         H_LOCK;
3693                         if (code) {
3694                             if (MultiProbeAlternateAddress_r(host)) {
3695                                 ViceLog(0,("CheckHost_r: Probing all interfaces of host %s:%d failed, code %d\n",
3696                                             hoststr, ntohs(host->port), code));
3697                                 host->hostFlags |= VENUSDOWN;
3698                             }
3699                         }
3700                     } else {
3701                         H_UNLOCK;
3702                         code = RXAFSCB_Probe(cb_conn);
3703                         H_LOCK;
3704                         if (code) {
3705                             ViceLog(0,
3706                                     ("CheckHost_r: Probe failed for host %s:%d, code %d\n", 
3707                                      hoststr, ntohs(host->port), code));
3708                             host->hostFlags |= VENUSDOWN;
3709                         }
3710                     }
3711                 }
3712             }
3713             H_UNLOCK;
3714             rx_PutConnection(cb_conn);
3715             cb_conn=NULL;
3716             H_LOCK;
3717         }
3718         h_Unlock_r(host);
3719     }
3720     return flags;
3721
3722 }                               /*CheckHost_r */
3723
3724
3725 /*
3726  * Set VenusDown for any hosts that have not had a call in 15 minutes and
3727  * don't respond to a probe.  Note that VenusDown can only be cleared if
3728  * a message is received from the host (see ServerLWP in file.c).
3729  * Delete hosts that have not had any calls in 1 hour, clients that
3730  * have not had any calls in 15 minutes.
3731  *
3732  * This routine is called roughly every 5 minutes.
3733  */
3734 void
3735 h_CheckHosts(void)
3736 {
3737     afs_uint32 now = FT_ApproxTime();
3738
3739     memset(&zerofid, 0, sizeof(zerofid));
3740     /*
3741      * Send a probe to the workstation if it hasn't been heard from in
3742      * 15 minutes
3743      */
3744     checktime = now - 15 * 60;
3745     clientdeletetime = now - 120 * 60;  /* 2 hours ago */
3746     
3747     H_LOCK;
3748     h_Enumerate_r(CheckHost_r, hostList, NULL);
3749     H_UNLOCK;
3750 }                               /*h_CheckHosts */
3751
3752 /*
3753  * This is called with host locked and held. At this point, the
3754  * hostAddrHashTable has an entry for the primary addr/port inserted
3755  * by h_Alloc_r().  No other interfaces should be considered valid.
3756  *
3757  * The addresses in the interfaceAddr list are in host byte order.
3758  */
3759 int
3760 initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
3761 {
3762     int i, j;
3763     int number, count;
3764     afs_uint32 myAddr;
3765     afs_uint16 myPort;
3766     int found;
3767     struct Interface *interface;
3768     char hoststr[16];
3769     char uuidstr[128];
3770     afs_uint16 port7001 = htons(7001);
3771
3772     assert(host);
3773     assert(interf);
3774
3775     number = interf->numberOfInterfaces;
3776     myAddr = host->host;        /* current interface address */
3777     myPort = host->port;        /* current port */
3778
3779     ViceLog(125,
3780             ("initInterfaceAddr : host %s:%d numAddr %d\n", 
3781               afs_inet_ntoa_r(myAddr, hoststr), ntohs(myPort), number));
3782
3783     /* validation checks */
3784     if (number < 0 || number > AFS_MAX_INTERFACE_ADDR) {
3785         ViceLog(0,
3786                 ("Invalid number of alternate addresses is %d\n", number));
3787         return -1;
3788     }
3789
3790     /*
3791      * The client's notion of its own IP addresses is not reliable.  
3792      *
3793      * 1. The client list might contain private address ranges which
3794      *    are likely to be re-used by many clients allocated addresses
3795      *    by a NAT.
3796      *
3797      * 2. The client list will not include any public addresses that
3798      *    are hidden by a NAT.
3799      *
3800      * 3. Private address ranges that are exposed to the server will
3801      *    be obtained from the rx connections that use them.
3802      *
3803      * 4. Lists provided by the client are not necessarily truthful.
3804      *    Many existing clients (UNIX) do not refresh the IP address
3805      *    list as the actual assigned addresses change.  The end result
3806      *    is that they report the initial address list for the lifetime
3807      *    of the process.  In other words, a client can report addresses
3808      *    that they are in fact not using.  Adding these addresses to
3809      *    the host interface list without verification is not only
3810      *    pointless, it is downright dangerous.
3811      *
3812      * We therefore do not add alternate addresses to the addr hash table.
3813      * We only use them for multi-rx callback breaks.
3814      */
3815
3816     /*
3817      * Convert IP addresses to network byte order, and remove
3818      * duplicate IP addresses from the interface list, and 
3819      * determine whether or not the incoming addr/port is 
3820      * listed.  Note that if the address matches it is not
3821      * truly a match because the port number for the entries
3822      * in the interface list are port 7001 and the port number
3823      * for this connection might not be 7001.
3824      */
3825     for (i = 0, count = 0, found = 0; i < number; i++) {
3826         interf->addr_in[i] = htonl(interf->addr_in[i]);
3827         for (j = 0; j < count; j++) {
3828             if (interf->addr_in[j] == interf->addr_in[i])
3829                 break;
3830         }
3831         if (j == count) {
3832             interf->addr_in[count] = interf->addr_in[i];
3833             if (interf->addr_in[count] == myAddr &&
3834                 port7001 == myPort)
3835                 found = 1;
3836             count++;
3837         }
3838     }
3839
3840     /*
3841      * Allocate and initialize an interface structure for this host.
3842      */
3843     if (found) {
3844         interface = (struct Interface *)
3845             malloc(sizeof(struct Interface) +
3846                    (sizeof(struct AddrPort) * (count - 1)));
3847         if (!interface) {
3848             ViceLog(0, ("Failed malloc in initInterfaceAddr_r 1\n"));
3849             assert(0);
3850         }
3851         interface->numberOfInterfaces = count;
3852     } else {
3853         interface = (struct Interface *)
3854             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * count));
3855         if (!interface) {
3856             ViceLog(0, ("Failed malloc in initInterfaceAddr_r 2\n"));
3857             assert(0);
3858         }
3859         interface->numberOfInterfaces = count + 1;
3860         interface->interface[count].addr = myAddr;
3861         interface->interface[count].port = myPort;
3862         interface->interface[count].valid = 1;
3863     }
3864
3865     for (i = 0; i < count; i++) {
3866
3867         interface->interface[i].addr = interf->addr_in[i];
3868         /* We store the port as 7001 because the addresses reported by 
3869          * TellMeAboutYourself and WhoAreYou RPCs are only valid if they
3870          * are coming from fully connected hosts (no NAT/PATs)
3871          */
3872         interface->interface[i].port = port7001;
3873         interface->interface[i].valid = 
3874             (interf->addr_in[i] == myAddr && port7001 == myPort) ? 1 : 0;
3875     }
3876
3877     interface->uuid = interf->uuid;
3878
3879     assert(!host->interface);
3880     host->interface = interface;
3881
3882     if (LogLevel >= 125) {
3883         afsUUID_to_string(&interface->uuid, uuidstr, 127);
3884         
3885         ViceLog(125, ("--- uuid %s\n", uuidstr));
3886         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
3887             ViceLog(125, ("--- alt address %s:%d\n", 
3888                           afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
3889                           ntohs(host->interface->interface[i].port)));
3890         }
3891     }
3892
3893     return 0;
3894 }
3895
3896 /* deleted a HashChain structure for this address and host */
3897 /* returns 1 on success */
3898 int
3899 h_DeleteHostFromAddrHashTable_r(afs_uint32 addr, afs_uint16 port, 
3900                                 struct host *host)
3901 {
3902     char hoststr[16];
3903     register struct h_AddrHashChain **hp, *th;
3904
3905     if (addr == 0 && port == 0)
3906         return 1;
3907
3908     for (hp = &hostAddrHashTable[h_HashIndex(addr)]; (th = *hp); 
3909          hp = &th->next) {
3910         assert(th->hostPtr);
3911         if (th->hostPtr == host && th->addr == addr && th->port == port) {
3912             ViceLog(125, ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT " (%s:%d)\n",
3913                           host, afs_inet_ntoa_r(host->host, hoststr),
3914                           ntohs(host->port)));
3915             *hp = th->next;
3916             free(th);
3917             return 1;
3918         }
3919     }
3920     ViceLog(125, 
3921             ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT " (%s:%d) not found\n",
3922              host, afs_inet_ntoa_r(host->host, hoststr), 
3923              ntohs(host->port)));
3924     return 0;
3925 }
3926
3927
3928 /*
3929 ** prints out all alternate interface address for the host. The 'level'
3930 ** parameter indicates what level of debugging sets this output
3931 */
3932 void
3933 printInterfaceAddr(struct host *host, int level)
3934 {
3935     int i, number;
3936     char hoststr[16];
3937
3938     if (host->interface) {
3939         /* check alternate addresses */
3940         number = host->interface->numberOfInterfaces;
3941         if (number == 0) {
3942             ViceLog(level, ("no-addresses "));
3943         } else {
3944             for (i = 0; i < number; i++)
3945                 ViceLog(level, ("%s:%d ", afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
3946                                 ntohs(host->interface->interface[i].port)));
3947         }
3948     }
3949     ViceLog(level, ("\n"));
3950 }