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