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