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