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