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