viced-log-typo-20060210
[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
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <stdio.h>
17 #include <errno.h>
18 #ifdef AFS_NT40_ENV
19 #include <fcntl.h>
20 #include <winsock2.h>
21 #else
22 #include <sys/file.h>
23 #include <netdb.h>
24 #include <netinet/in.h>
25 #endif
26
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #endif
34
35 #include <afs/stds.h>
36 #include <rx/xdr.h>
37 #include <afs/assert.h>
38 #include <lwp.h>
39 #include <lock.h>
40 #include <afs/afsint.h>
41 #include <afs/rxgen_consts.h>
42 #include <afs/nfs.h>
43 #include <afs/errors.h>
44 #include <afs/ihandle.h>
45 #include <afs/vnode.h>
46 #include <afs/volume.h>
47 #ifdef AFS_ATHENA_STDENV
48 #include <krb.h>
49 #endif
50 #include <afs/acl.h>
51 #include <afs/ptclient.h>
52 #include <afs/prs_fs.h>
53 #include <afs/auth.h>
54 #include <afs/afsutil.h>
55 #include <rx/rx.h>
56 #include <afs/cellconfig.h>
57 #include <stdlib.h>
58 #include "viced_prototypes.h"
59 #include "viced.h"
60 #include "host.h"
61
62
63 #ifdef AFS_PTHREAD_ENV
64 pthread_mutex_t host_glock_mutex;
65 #endif /* AFS_PTHREAD_ENV */
66
67 extern int Console;
68 extern int CurrentConnections;
69 extern int SystemId;
70 extern int AnonymousID;
71 extern prlist AnonCPS;
72 extern int LogLevel;
73 extern struct afsconf_dir *confDir;     /* config dir object */
74 extern int lwps;                /* the max number of server threads */
75 extern afsUUID FS_HostUUID;
76
77 int CEs = 0;                    /* active clients */
78 int CEBlocks = 0;               /* number of blocks of CEs */
79 struct client *CEFree = 0;      /* first free client */
80 struct host *hostList = 0;      /* linked list of all hosts */
81 int hostCount = 0;              /* number of hosts in hostList */
82 int rxcon_ident_key;
83 int rxcon_client_key;
84
85 #define CESPERBLOCK 73
86 struct CEBlock {                /* block of CESPERBLOCK file entries */
87     struct client entry[CESPERBLOCK];
88 };
89
90 static void h_TossStuff_r(register struct host *host);
91
92 /*
93  * Make sure the subnet macros have been defined.
94  */
95 #ifndef IN_SUBNETA
96 #define IN_SUBNETA(i)           ((((afs_int32)(i))&0x80800000)==0x00800000)
97 #endif
98
99 #ifndef IN_CLASSA_SUBNET
100 #define IN_CLASSA_SUBNET        0xffff0000
101 #endif
102
103 #ifndef IN_SUBNETB
104 #define IN_SUBNETB(i)           ((((afs_int32)(i))&0xc0008000)==0x80008000)
105 #endif
106
107 #ifndef IN_CLASSB_SUBNET
108 #define IN_CLASSB_SUBNET        0xffffff00
109 #endif
110
111
112 /* get a new block of CEs and chain it on CEFree */
113 static void
114 GetCEBlock()
115 {
116     register struct CEBlock *block;
117     register int i;
118
119     block = (struct CEBlock *)malloc(sizeof(struct CEBlock));
120     if (!block) {
121         ViceLog(0, ("Failed malloc in GetCEBlock\n"));
122         ShutDownAndCore(PANIC);
123     }
124
125     for (i = 0; i < (CESPERBLOCK - 1); i++) {
126         Lock_Init(&block->entry[i].lock);
127         block->entry[i].next = &(block->entry[i + 1]);
128     }
129     block->entry[CESPERBLOCK - 1].next = 0;
130     Lock_Init(&block->entry[CESPERBLOCK - 1].lock);
131     CEFree = (struct client *)block;
132     CEBlocks++;
133
134 }                               /*GetCEBlock */
135
136
137 /* get the next available CE */
138 static struct client *
139 GetCE()
140 {
141     register struct client *entry;
142
143     if (CEFree == 0)
144         GetCEBlock();
145     if (CEFree == 0) {
146         ViceLog(0, ("CEFree NULL in GetCE\n"));
147         ShutDownAndCore(PANIC);
148     }
149
150     entry = CEFree;
151     CEFree = entry->next;
152     CEs++;
153     memset((char *)entry, 0, CLIENT_TO_ZERO(entry));
154     return (entry);
155
156 }                               /*GetCE */
157
158
159 /* return an entry to the free list */
160 static void
161 FreeCE(register struct client *entry)
162 {
163     entry->next = CEFree;
164     CEFree = entry;
165     CEs--;
166
167 }                               /*FreeCE */
168
169 /*
170  * The HTs and HTBlocks variables were formerly static, but they are
171  * now referenced elsewhere in the FileServer.
172  */
173 int HTs = 0;                    /* active file entries */
174 int HTBlocks = 0;               /* number of blocks of HTs */
175 static struct host *HTFree = 0; /* first free file entry */
176
177 /*
178  * Hash tables of host pointers. We need two tables, one
179  * to map IP addresses onto host pointers, and another
180  * to map host UUIDs onto host pointers.
181  */
182 static struct h_hashChain *hostHashTable[h_HASHENTRIES];
183 static struct h_hashChain *hostUuidHashTable[h_HASHENTRIES];
184 #define h_HashIndex(hostip) ((hostip) & (h_HASHENTRIES-1))
185 #define h_UuidHashIndex(uuidp) (((int)(afs_uuid_hash(uuidp))) & (h_HASHENTRIES-1))
186
187 struct HTBlock {                /* block of HTSPERBLOCK file entries */
188     struct host entry[h_HTSPERBLOCK];
189 };
190
191
192 /* get a new block of HTs and chain it on HTFree */
193 static void
194 GetHTBlock()
195 {
196     register struct HTBlock *block;
197     register int i;
198     static int index = 0;
199
200     block = (struct HTBlock *)malloc(sizeof(struct HTBlock));
201     if (!block) {
202         ViceLog(0, ("Failed malloc in GetHTBlock\n"));
203         ShutDownAndCore(PANIC);
204     }
205 #ifdef AFS_PTHREAD_ENV
206     for (i = 0; i < (h_HTSPERBLOCK); i++)
207         assert(pthread_cond_init(&block->entry[i].cond, NULL) == 0);
208 #endif /* AFS_PTHREAD_ENV */
209     for (i = 0; i < (h_HTSPERBLOCK); i++)
210         Lock_Init(&block->entry[i].lock);
211     for (i = 0; i < (h_HTSPERBLOCK - 1); i++)
212         block->entry[i].next = &(block->entry[i + 1]);
213     for (i = 0; i < (h_HTSPERBLOCK); i++)
214         block->entry[i].index = index++;
215     block->entry[h_HTSPERBLOCK - 1].next = 0;
216     HTFree = (struct host *)block;
217     hosttableptrs[HTBlocks++] = block->entry;
218
219 }                               /*GetHTBlock */
220
221
222 /* get the next available HT */
223 static struct host *
224 GetHT()
225 {
226     register struct host *entry;
227
228     if (HTFree == 0)
229         GetHTBlock();
230     assert(HTFree != 0);
231     entry = HTFree;
232     HTFree = entry->next;
233     HTs++;
234     memset((char *)entry, 0, HOST_TO_ZERO(entry));
235     return (entry);
236
237 }                               /*GetHT */
238
239
240 /* return an entry to the free list */
241 static void
242 FreeHT(register struct host *entry)
243 {
244     entry->next = HTFree;
245     HTFree = entry;
246     HTs--;
247
248 }                               /*FreeHT */
249
250
251 static short consolePort = 0;
252
253 int
254 h_Release(register struct host *host)
255 {
256     H_LOCK;
257     h_Release_r(host);
258     H_UNLOCK;
259     return 0;
260 }
261
262 /**
263  * If this thread does not have a hold on this host AND
264  * if other threads also dont have any holds on this host AND
265  * If either the HOSTDELETED or CLIENTDELETED flags are set
266  * then toss the host
267  */
268 int
269 h_Release_r(register struct host *host)
270 {
271
272     if (!((host)->holds[h_holdSlot()] & ~h_holdbit())) {
273         if (!h_OtherHolds_r(host)) {
274             /* must avoid masking this until after h_OtherHolds_r runs
275              * but it should be run before h_TossStuff_r */
276             (host)->holds[h_holdSlot()] &= ~h_holdbit();
277             if ((host->hostFlags & HOSTDELETED)
278                 || (host->hostFlags & CLIENTDELETED)) {
279                 h_TossStuff_r(host);
280             }
281         } else
282             (host)->holds[h_holdSlot()] &= ~h_holdbit();
283     } else
284         (host)->holds[h_holdSlot()] &= ~h_holdbit();
285
286     return 0;
287 }
288
289 int
290 h_OtherHolds_r(register struct host *host)
291 {
292     register int i, bit, slot;
293     bit = h_holdbit();
294     slot = h_holdSlot();
295     for (i = 0; i < h_maxSlots; i++) {
296         if (host->holds[i] != ((i == slot) ? bit : 0)) {
297             return 1;
298         }
299     }
300     return 0;
301 }
302
303 int
304 h_Lock_r(register struct host *host)
305 {
306     H_UNLOCK;
307     h_Lock(host);
308     H_LOCK;
309     return 0;
310 }
311
312 /**
313   * Non-blocking lock
314   * returns 1 if already locked
315   * else returns locks and returns 0
316   */
317
318 int
319 h_NBLock_r(register struct host *host)
320 {
321     struct Lock *hostLock = &host->lock;
322     int locked = 0;
323
324     H_UNLOCK;
325     LOCK_LOCK(hostLock);
326     if (!(hostLock->excl_locked) && !(hostLock->readers_reading))
327         hostLock->excl_locked = WRITE_LOCK;
328     else
329         locked = 1;
330
331     LOCK_UNLOCK(hostLock);
332     H_LOCK;
333     if (locked)
334         return 1;
335     else
336         return 0;
337 }
338
339
340 #if FS_STATS_DETAILED
341 /*------------------------------------------------------------------------
342  * PRIVATE h_AddrInSameNetwork
343  *
344  * Description:
345  *      Given a target IP address and a candidate IP address (both
346  *      in host byte order), return a non-zero value (1) if the
347  *      candidate address is in a different network from the target
348  *      address.
349  *
350  * Arguments:
351  *      a_targetAddr       : Target address.
352  *      a_candAddr         : Candidate address.
353  *
354  * Returns:
355  *      1 if the candidate address is in the same net as the target,
356  *      0 otherwise.
357  *
358  * Environment:
359  *      The target and candidate addresses are both in host byte
360  *      order, NOT network byte order, when passed in.  We return
361  *      our value as a character, since that's the type of field in
362  *      the host structure, where this info will be stored.
363  *
364  * Side Effects:
365  *      As advertised.
366  *------------------------------------------------------------------------*/
367
368 static char
369 h_AddrInSameNetwork(afs_uint32 a_targetAddr, afs_uint32 a_candAddr)
370 {                               /*h_AddrInSameNetwork */
371
372     afs_uint32 targetNet;
373     afs_uint32 candNet;
374
375     /*
376      * Pull out the network and subnetwork numbers from the target
377      * and candidate addresses.  We can short-circuit this whole
378      * affair if the target and candidate addresses are not of the
379      * same class.
380      */
381     if (IN_CLASSA(a_targetAddr)) {
382         if (!(IN_CLASSA(a_candAddr))) {
383             return (0);
384         }
385         targetNet = a_targetAddr & IN_CLASSA_NET;
386         candNet = a_candAddr & IN_CLASSA_NET;
387     } else if (IN_CLASSB(a_targetAddr)) {
388         if (!(IN_CLASSB(a_candAddr))) {
389             return (0);
390         }
391         targetNet = a_targetAddr & IN_CLASSB_NET;
392         candNet = a_candAddr & IN_CLASSB_NET;
393     } /*Class B target */
394     else if (IN_CLASSC(a_targetAddr)) {
395         if (!(IN_CLASSC(a_candAddr))) {
396             return (0);
397         }
398         targetNet = a_targetAddr & IN_CLASSC_NET;
399         candNet = a_candAddr & IN_CLASSC_NET;
400     } /*Class C target */
401     else {
402         targetNet = a_targetAddr;
403         candNet = a_candAddr;
404     }                           /*Class D address */
405
406     /*
407      * Now, simply compare the extracted net values for the two addresses
408      * (which at this point are known to be of the same class)
409      */
410     if (targetNet == candNet)
411         return (1);
412     else
413         return (0);
414
415 }                               /*h_AddrInSameNetwork */
416 #endif /* FS_STATS_DETAILED */
417
418
419 /* Assumptions: called with held host */
420 void
421 h_gethostcps_r(register struct host *host, register afs_int32 now)
422 {
423     register int code;
424     int slept = 0;
425
426     /* wait if somebody else is already doing the getCPS call */
427     while (host->hostFlags & HCPS_INPROGRESS) {
428         slept = 1;              /* I did sleep */
429         host->hostFlags |= HCPS_WAITING;        /* I am sleeping now */
430 #ifdef AFS_PTHREAD_ENV
431         pthread_cond_wait(&host->cond, &host_glock_mutex);
432 #else /* AFS_PTHREAD_ENV */
433         if ((code = LWP_WaitProcess(&(host->hostFlags))) != LWP_SUCCESS)
434             ViceLog(0, ("LWP_WaitProcess returned %d\n", code));
435 #endif /* AFS_PTHREAD_ENV */
436     }
437
438
439     host->hostFlags |= HCPS_INPROGRESS; /* mark as CPSCall in progress */
440     if (host->hcps.prlist_val)
441         free(host->hcps.prlist_val);    /* this is for hostaclRefresh */
442     host->hcps.prlist_val = NULL;
443     host->hcps.prlist_len = 0;
444     slept ? (host->cpsCall = FT_ApproxTime()) : (host->cpsCall = now);
445
446     H_UNLOCK;
447     code = pr_GetHostCPS(htonl(host->host), &host->hcps);
448     H_LOCK;
449     if (code) {
450         /*
451          * Although ubik_Call (called by pr_GetHostCPS) traverses thru all protection servers
452          * and reevaluates things if no sync server or quorum is found we could still end up
453          * with one of these errors. In such case we would like to reevaluate the rpc call to
454          * find if there's cps for this guy. We treat other errors (except network failures
455          * ones - i.e. code < 0) as an indication that there is no CPS for this host. Ideally
456          * we could like to deal this problem the other way around (i.e. if code == NOCPS 
457          * ignore else retry next time) but the problem is that there're other errors (i.e.
458          * EPERM) for which we don't want to retry and we don't know the whole code list!
459          */
460         if (code < 0 || code == UNOQUORUM || code == UNOTSYNC) {
461             /* 
462              * We would have preferred to use a while loop and try again since ops in protected
463              * acls for this host will fail now but they'll be reevaluated on any subsequent
464              * call. The attempt to wait for a quorum/sync site or network error won't work
465              * since this problems really should only occurs during a complete fileserver 
466              * restart. Since the fileserver will start before the ptservers (and thus before
467              * quorums are complete) clients will be utilizing all the fileserver's lwps!!
468              */
469             host->hcpsfailed = 1;
470             ViceLog(0,
471                     ("Warning:  GetHostCPS failed (%d) for %x; will retry\n",
472                      code, host->host));
473         } else {
474             host->hcpsfailed = 0;
475             ViceLog(1,
476                     ("gethost:  GetHostCPS failed (%d) for %x; ignored\n",
477                      code, host->host));
478         }
479         if (host->hcps.prlist_val)
480             free(host->hcps.prlist_val);
481         host->hcps.prlist_val = NULL;
482         host->hcps.prlist_len = 0;      /* Make sure it's zero */
483     } else
484         host->hcpsfailed = 0;
485
486     host->hostFlags &= ~HCPS_INPROGRESS;
487     /* signal all who are waiting */
488     if (host->hostFlags & HCPS_WAITING) {       /* somebody is waiting */
489         host->hostFlags &= ~HCPS_WAITING;
490 #ifdef AFS_PTHREAD_ENV
491         assert(pthread_cond_broadcast(&host->cond) == 0);
492 #else /* AFS_PTHREAD_ENV */
493         if ((code = LWP_NoYieldSignal(&(host->hostFlags))) != LWP_SUCCESS)
494             ViceLog(0, ("LWP_NoYieldSignal returns %d\n", code));
495 #endif /* AFS_PTHREAD_ENV */
496     }
497 }
498
499 /* args in net byte order */
500 void
501 h_flushhostcps(register afs_uint32 hostaddr, register afs_uint32 hport)
502 {
503     register struct host *host;
504     int held = 0;
505
506     H_LOCK;
507     host = h_Lookup_r(hostaddr, hport, &held);
508     if (host) {
509         host->hcpsfailed = 1;
510         if (!held)
511             h_Release_r(host);
512     }
513     H_UNLOCK;
514     return;
515 }
516
517
518 /*
519  * Allocate a host.  It will be identified by the peer (ip,port) info in the
520  * rx connection provided.  The host is returned held and locked
521  */
522 #define DEF_ROPCONS 2115
523
524 struct host *
525 h_Alloc_r(register struct rx_connection *r_con)
526 {
527     struct servent *serverentry;
528     register index = h_HashIndex(rxr_HostOf(r_con));
529     register struct host *host;
530     static struct rx_securityClass *sc = 0;
531     afs_int32 now;
532     struct h_hashChain *h_hashChain;
533 #if FS_STATS_DETAILED
534     afs_uint32 newHostAddr_HBO; /*New host IP addr, in host byte order */
535 #endif /* FS_STATS_DETAILED */
536
537     host = GetHT();
538
539     h_hashChain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
540     if (!h_hashChain) {
541         ViceLog(0, ("Failed malloc in h_Alloc_r\n"));
542         assert(0);
543     }
544     h_hashChain->hostPtr = host;
545     h_hashChain->addr = rxr_HostOf(r_con);
546     h_hashChain->next = hostHashTable[index];
547     hostHashTable[index] = h_hashChain;
548
549     host->host = rxr_HostOf(r_con);
550     host->port = rxr_PortOf(r_con);
551     if (consolePort == 0) {     /* find the portal number for console */
552 #if     defined(AFS_OSF_ENV)
553         serverentry = getservbyname("ropcons", "");
554 #else
555         serverentry = getservbyname("ropcons", 0);
556 #endif
557         if (serverentry)
558             consolePort = serverentry->s_port;
559         else
560             consolePort = htons(DEF_ROPCONS);   /* Use a default */
561     }
562     if (host->port == consolePort)
563         host->Console = 1;
564     /* Make a callback channel even for the console, on the off chance that it
565      * makes a request that causes a break call back.  It shouldn't. */
566     {
567         if (!sc)
568             sc = rxnull_NewClientSecurityObject();
569         host->callback_rxcon =
570             rx_NewConnection(host->host, host->port, 1, sc, 0);
571         rx_SetConnDeadTime(host->callback_rxcon, 50);
572         rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
573     }
574     now = host->LastCall = host->cpsCall = host->ActiveCall = FT_ApproxTime();
575     host->hostFlags = 0;
576     host->hcps.prlist_val = NULL;
577     host->hcps.prlist_len = 0;
578     host->interface = 0;
579 #ifdef undef
580     host->hcpsfailed = 0;       /* save cycles */
581     h_gethostcps(host);         /* do this under host hold/lock */
582 #endif
583     host->FirstClient = 0;
584     h_Hold_r(host);
585     h_Lock_r(host);
586     h_InsertList_r(host);       /* update global host List */
587 #if FS_STATS_DETAILED
588     /*
589      * Compare the new host's IP address (in host byte order) with ours
590      * (the File Server's), remembering if they are in the same network.
591      */
592     newHostAddr_HBO = (afs_uint32) ntohl(host->host);
593     host->InSameNetwork =
594         h_AddrInSameNetwork(FS_HostAddr_HBO, newHostAddr_HBO);
595 #endif /* FS_STATS_DETAILED */
596     return host;
597
598 }                               /*h_Alloc_r */
599
600
601 /* Lookup a host given an IP address and UDP port number. */
602 /* hostaddr and hport are in network order */
603 /* Note: host should be released by caller if 0 == *heldp and non-null */
604 /* hostaddr and hport are in network order */
605 struct host *
606 h_Lookup_r(afs_uint32 haddr, afs_uint32 hport, int *heldp)
607 {
608     register afs_int32 now;
609     register struct host *host = 0;
610     register struct h_hashChain *chain;
611     register index = h_HashIndex(haddr);
612     extern int hostaclRefresh;
613
614   restart:
615     for (chain = hostHashTable[index]; chain; chain = chain->next) {
616         host = chain->hostPtr;
617         assert(host);
618         if (!(host->hostFlags & HOSTDELETED) && chain->addr == haddr
619             && chain->port == hport) {
620             *heldp = h_Held_r(host);
621             if (!*heldp)
622                 h_Hold_r(host);
623             h_Lock_r(host);
624             if (host->hostFlags & HOSTDELETED) {
625                 h_Unlock_r(host);
626                 if (!*heldp)
627                     h_Release_r(host);
628                 goto restart;
629             }
630             h_Unlock_r(host);
631             now = FT_ApproxTime();      /* always evaluate "now" */
632             if (host->hcpsfailed || (host->cpsCall + hostaclRefresh < now)) {
633                 /*
634                  * Every hostaclRefresh period (def 2 hrs) get the new
635                  * membership list for the host.  Note this could be the
636                  * first time that the host is added to a group.  Also
637                  * here we also retry on previous legitimate hcps failures.
638                  *
639                  * If we get here we still have a host hold.
640                  */
641                 h_gethostcps_r(host, now);
642             }
643             break;
644         }
645         host = NULL;
646     }
647     return host;
648
649 }                               /*h_Lookup */
650
651 /* Lookup a host given its UUID. */
652 struct host *
653 h_LookupUuid_r(afsUUID * uuidp)
654 {
655     register struct host *host = 0;
656     register struct h_hashChain *chain;
657     register index = h_UuidHashIndex(uuidp);
658
659     for (chain = hostUuidHashTable[index]; chain; chain = chain->next) {
660         host = chain->hostPtr;
661         assert(host);
662         if (!(host->hostFlags & HOSTDELETED) && host->interface
663             && afs_uuid_equal(&host->interface->uuid, uuidp)) {
664             break;
665         }
666         host = NULL;
667     }
668     return host;
669
670 }                               /*h_Lookup */
671
672
673 /*
674  * h_Hold_r: Establish a hold by the current LWP on this host--the host
675  * or its clients will not be physically deleted until all holds have
676  * been released.
677  * NOTE: h_Hold_r is a macro defined in host.h.
678  */
679
680 /* h_TossStuff_r:  Toss anything in the host structure (the host or
681  * clients marked for deletion.  Called from h_Release_r ONLY.
682  * To be called, there must be no holds, and either host->deleted
683  * or host->clientDeleted must be set.
684  */
685 static void
686 h_TossStuff_r(register struct host *host)
687 {
688     register struct client **cp, *client;
689     int i;
690
691     /* if somebody still has this host held */
692     for (i = 0; (i < h_maxSlots) && (!(host)->holds[i]); i++);
693     if (i != h_maxSlots)
694         return;
695
696     /* if somebody still has this host locked */
697     if (h_NBLock_r(host) != 0) {
698         char hoststr[16];
699         ViceLog(0,
700                 ("Warning:  h_TossStuff_r failed; Host %s:%d was locked.\n",
701                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
702         return;
703     } else {
704         h_Unlock_r(host);
705     }
706
707     /* ASSUMPTION: rxi_FreeConnection() does not yield */
708     for (cp = &host->FirstClient; (client = *cp);) {
709         if ((host->hostFlags & HOSTDELETED) || client->deleted) {
710             if (client->refCount) {
711                 char hoststr[16];
712                 ViceLog(0,
713                         ("Warning: Host %s:%d client %x refcount %d while deleting.\n",
714                          afs_inet_ntoa_r(host->host, hoststr),
715                          ntohs(host->port), client, client->refCount));
716             }
717             if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) {
718                 free(client->CPS.prlist_val);
719                 client->CPS.prlist_val = NULL;
720             }
721             client->CPS.prlist_len = 0;
722             if (client->tcon) {
723                 rx_SetSpecific(client->tcon, rxcon_client_key, (void *)0);
724             }
725             CurrentConnections--;
726             *cp = client->next;
727             FreeCE(client);
728         } else
729             cp = &client->next;
730     }
731
732     /* We've just cleaned out all the deleted clients; clear the flag */
733     host->hostFlags &= ~CLIENTDELETED;
734
735     if (host->hostFlags & HOSTDELETED) {
736         register struct h_hashChain **hp, *th;
737         register struct rx_connection *rxconn;
738         afsUUID *uuidp;
739         struct AddrPort hostAddrPort;
740         int i;
741
742         if (host->Console & 1)
743             Console--;
744         if ((rxconn = host->callback_rxcon)) {
745             host->callback_rxcon = (struct rx_connection *)0;
746             /*
747              * If rx_DestroyConnection calls h_FreeConnection we will
748              * deadlock on the host_glock_mutex. Work around the problem
749              * by unhooking the client from the connection before
750              * destroying the connection.
751              */
752             client = rx_GetSpecific(rxconn, rxcon_client_key);
753             if (client && client->tcon == rxconn)
754                 client->tcon = NULL;
755             rx_SetSpecific(rxconn, rxcon_client_key, (void *)0);
756             rx_DestroyConnection(rxconn);
757         }
758         if (host->hcps.prlist_val)
759             free(host->hcps.prlist_val);
760         host->hcps.prlist_val = NULL;
761         host->hcps.prlist_len = 0;
762         DeleteAllCallBacks_r(host, 1);
763         host->hostFlags &= ~RESETDONE;  /* just to be safe */
764
765         /* if alternate addresses do not exist */
766         if (!(host->interface)) {
767             for (hp = &hostHashTable[h_HashIndex(host->host)]; (th = *hp);
768                  hp = &th->next) {
769                 assert(th->hostPtr);
770                 if (th->hostPtr == host) {
771                     *hp = th->next;
772                     h_DeleteList_r(host);
773                     FreeHT(host);
774                     free(th);
775                     break;
776                 }
777             }
778         } else {
779             /* delete all hash entries for the UUID */
780             uuidp = &host->interface->uuid;
781             for (hp = &hostUuidHashTable[h_UuidHashIndex(uuidp)]; (th = *hp);
782                  hp = &th->next) {
783                 assert(th->hostPtr);
784                 if (th->hostPtr == host) {
785                     *hp = th->next;
786                     free(th);
787                     break;
788                 }
789             }
790             /* delete all hash entries for alternate addresses */
791             assert(host->interface->numberOfInterfaces > 0);
792             for (i = 0; i < host->interface->numberOfInterfaces; i++) {
793                 hostAddrPort = host->interface->interface[i];
794
795                 for (hp = &hostHashTable[h_HashIndex(hostAddrPort.addr)]; (th = *hp);
796                      hp = &th->next) {
797                     assert(th->hostPtr);
798                     if (th->hostPtr == host) {
799                         *hp = th->next;
800                         free(th);
801                         break;
802                     }
803                 }
804             }
805             free(host->interface);
806             host->interface = NULL;
807             h_DeleteList_r(host);       /* remove host from global host List */
808             FreeHT(host);
809         }                       /* if alternate address exists */
810     }
811 }                               /*h_TossStuff_r */
812
813
814 /* Called by rx when a server connection disappears */
815 int
816 h_FreeConnection(struct rx_connection *tcon)
817 {
818     register struct client *client;
819
820     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
821     if (client) {
822         H_LOCK;
823         if (client->tcon == tcon)
824             client->tcon = (struct rx_connection *)0;
825         H_UNLOCK;
826     }
827     return 0;
828 }                               /*h_FreeConnection */
829
830
831 /* h_Enumerate: Calls (*proc)(host, held, param) for at least each host in the
832  * system at the start of the enumeration (perhaps more).  Hosts may be deleted
833  * (have delete flag set); ditto for clients.  (*proc) is always called with
834  * host h_held().  The hold state of the host with respect to this lwp is passed
835  * to (*proc) as the param held.  The proc should return 0 if the host should be
836  * released, 1 if it should be held after enumeration.
837  */
838 void
839 h_Enumerate(int (*proc) (), char *param)
840 {
841     register struct host *host, **list;
842     register int *held;
843     register int i, count;
844
845     H_LOCK;
846     if (hostCount == 0) {
847         H_UNLOCK;
848         return;
849     }
850     list = (struct host **)malloc(hostCount * sizeof(struct host *));
851     if (!list) {
852         ViceLog(0, ("Failed malloc in h_Enumerate\n"));
853         assert(0);
854     }
855     held = (int *)malloc(hostCount * sizeof(int));
856     if (!held) {
857         ViceLog(0, ("Failed malloc in h_Enumerate\n"));
858         assert(0);
859     }
860     for (count = 0, host = hostList; host; host = host->next, count++) {
861         list[count] = host;
862         if (!(held[count] = h_Held_r(host)))
863             h_Hold_r(host);
864     }
865     assert(count == hostCount);
866     H_UNLOCK;
867     for (i = 0; i < count; i++) {
868         held[i] = (*proc) (list[i], held[i], param);
869         if (!held[i])
870             h_Release(list[i]); /* this might free up the host */
871     }
872     free((void *)list);
873     free((void *)held);
874 }                               /*h_Enumerate */
875
876 /* h_Enumerate_r (revised):
877  * Calls (*proc)(host, held, param) for each host in hostList, starting
878  * at enumstart
879  * Hosts may be deleted (have delete flag set); ditto for clients.
880  * (*proc) is always called with
881  * host h_held() and the global host lock (H_LOCK) locked.The hold state of the
882  * host with respect to this lwp is passed to (*proc) as the param held.
883  * The proc should return 0 if the host should be released, 1 if it should
884  * be held after enumeration.
885  */
886 void
887 h_Enumerate_r(int (*proc) (), struct host *enumstart, char *param)
888 {
889     register struct host *host, *next;
890     register int held, nheld;
891
892     if (hostCount == 0) {
893         return;
894     }
895     if (enumstart && !(held = h_Held_r(enumstart)))
896         h_Hold_r(enumstart); 
897     for (host = enumstart; host; host = next, held = nheld) {
898         held = (*proc) (host, held, param);
899         next = host->next;
900         if (next && !(nheld = h_Held_r(next)))
901             h_Hold_r(next);
902         if (!held)
903             h_Release_r(host); /* this might free up the host */
904     }
905 }                               /*h_Enumerate_r */
906
907 /* inserts a new HashChain structure corresponding to this UUID */
908 void
909 hashInsertUuid_r(struct afsUUID *uuid, struct host *host)
910 {
911     int index;
912     struct h_hashChain *chain;
913
914     /* hash into proper bucket */
915     index = h_UuidHashIndex(uuid);
916
917     /* insert into beginning of list for this bucket */
918     chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
919     if (!chain) {
920         ViceLog(0, ("Failed malloc in hashInsertUuid_r\n"));
921         assert(0);
922     }
923     assert(chain);
924     chain->hostPtr = host;
925     chain->next = hostUuidHashTable[index];
926     hostUuidHashTable[index] = chain;
927 }
928
929
930 /* inserts a new HashChain structure corresponding to this address */
931 void
932 hashInsert_r(afs_uint32 addr, afs_uint16 port, struct host *host)
933 {
934     int index;
935     struct h_hashChain *chain;
936
937     /* hash into proper bucket */
938     index = h_HashIndex(addr);
939
940     /* insert into beginning of list for this bucket */
941     chain = (struct h_hashChain *)malloc(sizeof(struct h_hashChain));
942     if (!chain) {
943         ViceLog(0, ("Failed malloc in hashInsert_r\n"));
944         assert(0);
945     }
946     chain->hostPtr = host;
947     chain->next = hostHashTable[index];
948     chain->addr = addr;
949     chain->port = port;
950     hostHashTable[index] = chain;
951
952 }
953
954 /*
955  * This is called with host locked and held. At this point, the
956  * hostHashTable should not be having entries for the alternate
957  * interfaces. This function has to insert these entries in the
958  * hostHashTable.
959  *
960  * All addresses are in network byte order.
961  */
962 int
963 addInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
964 {
965     int i;
966     int number;
967     int found;
968     struct Interface *interface;
969     char hoststr[16], hoststr2[16];
970
971     assert(host);
972     assert(host->interface);
973
974     ViceLog(125, ("addInterfaceAddr : host %s:d addr %s:%d\n", 
975                    afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), 
976                    afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
977
978     /*
979      * Make sure this address is on the list of known addresses
980      * for this host.
981      */
982     number = host->interface->numberOfInterfaces;
983     for (i = 0, found = 0; i < number && !found; i++) {
984         if (host->interface->interface[i].addr == addr &&
985             host->interface->interface[i].port == port)
986             found = 1;
987     }
988     if (!found) {
989         interface = (struct Interface *)
990             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * number));
991         if (!interface) {
992             ViceLog(0, ("Failed malloc in addInterfaceAddr_r\n"));
993             assert(0);
994         }
995         interface->numberOfInterfaces = number + 1;
996         interface->uuid = host->interface->uuid;
997         for (i = 0; i < number; i++)
998             interface->interface[i] = host->interface->interface[i];
999         interface->interface[number].addr = addr;
1000         interface->interface[number].port = port;
1001         free(host->interface);
1002         host->interface = interface;
1003     }
1004
1005     /*
1006      * Create a hash table entry for this address
1007      */
1008     hashInsert_r(addr, port, host);
1009
1010     return 0;
1011 }
1012
1013
1014 /*
1015  * This is called with host locked and held. At this point, the
1016  * hostHashTable should not be having entries for the alternate
1017  * interfaces. This function has to insert these entries in the
1018  * hostHashTable.
1019  *
1020  * All addresses are in network byte order.
1021  */
1022 int
1023 removeInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
1024 {
1025     int i;
1026     int number;
1027     int found;
1028     struct Interface *interface;
1029     char hoststr[16], hoststr2[16];
1030
1031     assert(host);
1032     assert(host->interface);
1033
1034     ViceLog(125, ("removeInterfaceAddr : host %s:%d addr %s:%d\n", 
1035                    afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), 
1036                    afs_inet_ntoa_r(addr, hoststr2), ntohs(port)));
1037
1038     /*
1039      * Make sure this address is on the list of known addresses
1040      * for this host.
1041      */
1042     interface = host->interface;
1043     number = host->interface->numberOfInterfaces;
1044     for (i = 0, found = 0; i < number; i++) {
1045         if (interface->interface[i].addr == addr &&
1046             interface->interface[i].port == port) {
1047             found = 1;
1048             break;
1049         }
1050     }
1051     if (found) {
1052         number--;
1053         for (; i < number; i++) {
1054             interface->interface[i].addr = interface->interface[i+1].addr;
1055             interface->interface[i].port = interface->interface[i+1].port;
1056         }
1057         interface->numberOfInterfaces = number;
1058     }
1059
1060     /*
1061      * Remove the hash table entry for this address
1062      */
1063     hashDelete_r(addr, port, host);
1064
1065     return 0;
1066 }
1067
1068
1069 /* Host is returned held */
1070 struct host *
1071 h_GetHost_r(struct rx_connection *tcon)
1072 {
1073     struct host *host;
1074     struct host *oldHost;
1075     int code;
1076     int held, oheld;
1077     struct interfaceAddr interf;
1078     int interfValid = 0;
1079     struct Identity *identP = NULL;
1080     afs_int32 haddr;
1081     afs_int16 hport;
1082     char hoststr[16], hoststr2[16];
1083     Capabilities caps;
1084     struct rx_connection *cb_conn = NULL;
1085
1086     caps.Capabilities_val = NULL;
1087
1088     haddr = rxr_HostOf(tcon);
1089     hport = rxr_PortOf(tcon);
1090   retry:
1091     if (caps.Capabilities_val)
1092         free(caps.Capabilities_val);
1093     caps.Capabilities_val = NULL;
1094     caps.Capabilities_len = 0;
1095
1096     code = 0;
1097     host = h_Lookup_r(haddr, hport, &held);
1098     identP = (struct Identity *)rx_GetSpecific(tcon, rxcon_ident_key);
1099     if (host && !identP && !(host->Console & 1)) {
1100         /* This is a new connection, and we already have a host
1101          * structure for this address. Verify that the identity
1102          * of the caller matches the identity in the host structure.
1103          */
1104         h_Lock_r(host);
1105         if (!(host->hostFlags & ALTADDR)) {
1106             /* Another thread is doing initialization */
1107             h_Unlock_r(host);
1108             if (!held)
1109                 h_Release_r(host);
1110             ViceLog(125,
1111                     ("Host %s:%d starting h_Lookup again\n",
1112                      afs_inet_ntoa_r(host->host, hoststr),
1113                      ntohs(host->port)));
1114             goto retry;
1115         }
1116         host->hostFlags &= ~ALTADDR;
1117         cb_conn = host->callback_rxcon;
1118         rx_GetConnection(cb_conn);
1119         H_UNLOCK;
1120         code =
1121             RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1122         if (code == RXGEN_OPCODE)
1123             code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1124         rx_PutConnection(cb_conn);
1125         cb_conn=NULL;
1126         H_LOCK;
1127         if (code == RXGEN_OPCODE) {
1128             identP = (struct Identity *)malloc(sizeof(struct Identity));
1129             if (!identP) {
1130                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1131                 assert(0);
1132             }
1133             identP->valid = 0;
1134             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1135             /* The host on this connection was unable to respond to 
1136              * the WhoAreYou. We will treat this as a new connection
1137              * from the existing host. The worst that can happen is
1138              * that we maintain some extra callback state information */
1139             if (host->interface) {
1140                 ViceLog(0,
1141                         ("Host %s:%d used to support WhoAreYou, deleting.\n",
1142                          afs_inet_ntoa_r(host->host, hoststr),
1143                          ntohs(host->port)));
1144                 host->hostFlags |= HOSTDELETED;
1145                 h_Unlock_r(host);
1146                 if (!held)
1147                     h_Release_r(host);
1148                 host = NULL;
1149                 goto retry;
1150             }
1151         } else if (code == 0) {
1152             interfValid = 1;
1153             identP = (struct Identity *)malloc(sizeof(struct Identity));
1154             if (!identP) {
1155                 ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1156                 assert(0);
1157             }
1158             identP->valid = 1;
1159             identP->uuid = interf.uuid;
1160             rx_SetSpecific(tcon, rxcon_ident_key, identP);
1161             /* Check whether the UUID on this connection matches
1162              * the UUID in the host structure. If they don't match
1163              * then this is not the same host as before. */
1164             if (!host->interface
1165                 || !afs_uuid_equal(&interf.uuid, &host->interface->uuid)) {
1166                 ViceLog(25,
1167                         ("Host %s:%d has changed its identity, deleting.\n",
1168                          afs_inet_ntoa_r(host->host, hoststr), host->port));
1169                 host->hostFlags |= HOSTDELETED;
1170                 h_Unlock_r(host);
1171                 if (!held)
1172                     h_Release_r(host);
1173                 host = NULL;
1174                 goto retry;
1175             }
1176         } else {
1177             afs_inet_ntoa_r(host->host, hoststr);
1178             ViceLog(0,
1179                     ("CB: WhoAreYou failed for %s:%d, error %d\n", hoststr,
1180                      ntohs(host->port), code));
1181             host->hostFlags |= VENUSDOWN;
1182         }
1183         if (caps.Capabilities_val
1184             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
1185             host->hostFlags |= HERRORTRANS;
1186         else
1187             host->hostFlags &= ~(HERRORTRANS);
1188         host->hostFlags |= ALTADDR;
1189         h_Unlock_r(host);
1190     } else if (host) {
1191         if (!(host->hostFlags & ALTADDR)) {
1192             /* another thread is doing the initialisation */
1193             ViceLog(125,
1194                     ("Host %s:%d waiting for host-init to complete\n",
1195                      afs_inet_ntoa_r(host->host, hoststr),
1196                      ntohs(host->port)));
1197             h_Lock_r(host);
1198             h_Unlock_r(host);
1199             if (!held)
1200                 h_Release_r(host);
1201             ViceLog(125,
1202                     ("Host %s:%d starting h_Lookup again\n",
1203                      afs_inet_ntoa_r(host->host, hoststr),
1204                      ntohs(host->port)));
1205             goto retry;
1206         }
1207         /* We need to check whether the identity in the host structure
1208          * matches the identity on the connection. If they don't match
1209          * then treat this a new host. */
1210         if (!(host->Console & 1)
1211             && ((!identP->valid && host->interface)
1212                 || (identP->valid && !host->interface)
1213                 || (identP->valid
1214                     && !afs_uuid_equal(&identP->uuid,
1215                                        &host->interface->uuid)))) {
1216             char uuid1[128], uuid2[128];
1217             if (identP->valid)
1218                 afsUUID_to_string(&identP->uuid, uuid1, 127);
1219             if (host->interface)
1220                 afsUUID_to_string(&host->interface->uuid, uuid2, 127);
1221             ViceLog(0,
1222                     ("CB: new identity for host %s:%d, deleting(%x %x %s %s)\n",
1223                      afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
1224                      identP->valid, host->interface,
1225                      identP->valid ? uuid1 : "",
1226                      host->interface ? uuid2 : ""));
1227
1228             /* The host in the cache is not the host for this connection */
1229             host->hostFlags |= HOSTDELETED;
1230             h_Unlock_r(host);
1231             if (!held)
1232                 h_Release_r(host);
1233             goto retry;
1234         }
1235     } else {
1236         host = h_Alloc_r(tcon); /* returned held and locked */
1237         h_gethostcps_r(host, FT_ApproxTime());
1238         if (!(host->Console & 1)) {
1239             int pident = 0;
1240             cb_conn = host->callback_rxcon;
1241             rx_GetConnection(cb_conn);
1242             H_UNLOCK;
1243             code =
1244                 RXAFSCB_TellMeAboutYourself(cb_conn, &interf, &caps);
1245             if (code == RXGEN_OPCODE)
1246                 code = RXAFSCB_WhoAreYou(cb_conn, &interf);
1247             rx_PutConnection(cb_conn);
1248             cb_conn=NULL;
1249             H_LOCK;
1250             if (code == RXGEN_OPCODE) {
1251                 if (!identP)
1252                     identP =
1253                         (struct Identity *)malloc(sizeof(struct Identity));
1254                 else
1255                     pident = 1;
1256
1257                 if (!identP) {
1258                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1259                     assert(0);
1260                 }
1261                 identP->valid = 0;
1262                 if (!pident)
1263                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1264                 ViceLog(25,
1265                         ("Host %s:%d does not support WhoAreYou.\n",
1266                          afs_inet_ntoa_r(host->host, hoststr),
1267                          ntohs(host->port)));
1268                 code = 0;
1269             } else if (code == 0) {
1270                 if (!identP)
1271                     identP =
1272                         (struct Identity *)malloc(sizeof(struct Identity));
1273                 else
1274                     pident = 1;
1275
1276                 if (!identP) {
1277                     ViceLog(0, ("Failed malloc in h_GetHost_r\n"));
1278                     assert(0);
1279                 }
1280                 identP->valid = 1;
1281                 interfValid = 1;
1282                 identP->uuid = interf.uuid;
1283                 if (!pident)
1284                     rx_SetSpecific(tcon, rxcon_ident_key, identP);
1285                 ViceLog(25,
1286                         ("WhoAreYou success on %s:%d\n",
1287                          afs_inet_ntoa_r(host->host, hoststr),
1288                          ntohs(host->port)));
1289             }
1290             if (code == 0 && !identP->valid) {
1291                 cb_conn = host->callback_rxcon;
1292                 rx_GetConnection(cb_conn);
1293                 H_UNLOCK;
1294                 code = RXAFSCB_InitCallBackState(cb_conn);
1295                 rx_PutConnection(cb_conn);
1296                 cb_conn=NULL;
1297                 H_LOCK;
1298             } else if (code == 0) {
1299                 oldHost = h_LookupUuid_r(&identP->uuid);
1300                 if (oldHost) {
1301                     int probefail = 0;
1302
1303                     if (!(oheld = h_Held_r(oldHost)))
1304                         h_Hold_r(oldHost);
1305                     h_Lock_r(oldHost);
1306
1307                     if (oldHost->interface) {
1308                         afsUUID uuid = oldHost->interface->uuid;
1309                         cb_conn = host->callback_rxcon;
1310                         rx_GetConnection(cb_conn);
1311                         H_UNLOCK;
1312                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
1313                         rx_PutConnection(cb_conn);
1314                         cb_conn=NULL;
1315                         H_LOCK;
1316                         if (code && MultiProbeAlternateAddress_r(oldHost)) {
1317                             probefail = 1;
1318                         }
1319                     } else {
1320                         probefail = 1;
1321                     }
1322
1323                     if (probefail) {
1324                         /* The old host is either does not have a Uuid,
1325                          * is not responding to Probes, 
1326                          * or does not have a matching Uuid. 
1327                          * Delete it! */
1328                         oldHost->hostFlags |= HOSTDELETED;
1329                         h_Unlock_r(oldHost);
1330                         /* Let the holder be last release */
1331                         if (!oheld) {
1332                             h_Release_r(oldHost);
1333                         }
1334                         oldHost = NULL;
1335                     }
1336                 }
1337                 if (oldHost) {
1338                     /* This is a new address for an existing host. Update
1339                      * the list of interfaces for the existing host and
1340                      * delete the host structure we just allocated. */
1341                     if (oldHost->host != haddr || oldHost->port != hport) {
1342                     ViceLog(25,
1343                             ("CB: new addr %s:%d for old host %s:%d\n",
1344                              afs_inet_ntoa_r(host->host, hoststr),
1345                                 ntohs(host->port), 
1346                                 afs_inet_ntoa_r(oldHost->host, hoststr2),
1347                              ntohs(oldHost->port)));
1348                         if (oldHost->host == haddr) {
1349                             /* We have just been contacted by a client behind a NAT */
1350                             removeInterfaceAddr_r(oldHost, oldHost->host, oldHost->port);
1351                         } else {
1352                             int i, found;
1353                             struct Interface *interface = oldHost->interface;
1354                             int number = oldHost->interface->numberOfInterfaces;
1355                             for (i = 0, found = 0; i < number; i++) {
1356                                 if (interface->interface[i].addr == haddr &&
1357                                     interface->interface[i].port != hport) {
1358                                     found = 1;
1359                                     break;
1360                                 }
1361                             }
1362                             if (found) {
1363                                 /* We have just been contacted by a client that has been
1364                                  * seen from behind a NAT and at least one other address.
1365                                  */
1366                                 removeInterfaceAddr_r(oldHost, haddr, interface->interface[i].port);
1367                             }
1368                         }
1369                     addInterfaceAddr_r(oldHost, haddr, hport);
1370                         oldHost->host = haddr;
1371                         oldHost->port = hport;
1372                     }
1373                     host->hostFlags |= HOSTDELETED;
1374                     h_Unlock_r(host);
1375                     if (!held)
1376                         h_Release_r(host);
1377                     host = oldHost;
1378                 } else {
1379                     /* This really is a new host */
1380                     hashInsertUuid_r(&identP->uuid, host);
1381                     cb_conn = host->callback_rxcon;
1382                     rx_GetConnection(cb_conn);          
1383                     H_UNLOCK;
1384                     code =
1385                         RXAFSCB_InitCallBackState3(cb_conn,
1386                                                    &FS_HostUUID);
1387                     rx_PutConnection(cb_conn);
1388                     cb_conn=NULL;
1389                     H_LOCK;
1390                     if (code == 0) {
1391                         ViceLog(25,
1392                                 ("InitCallBackState3 success on %s:%d\n",
1393                                  afs_inet_ntoa_r(host->host, hoststr),
1394                                  ntohs(host->port)));
1395                         assert(interfValid == 1);
1396                         initInterfaceAddr_r(host, &interf);
1397                     }
1398                 }
1399             }
1400             if (code) {
1401                 afs_inet_ntoa_r(host->host, hoststr);
1402                 ViceLog(0,
1403                         ("CB: RCallBackConnectBack failed for %s:%d\n",
1404                          hoststr, ntohs(host->port)));
1405                 host->hostFlags |= VENUSDOWN;
1406             } else {
1407                 ViceLog(125,
1408                         ("CB: RCallBackConnectBack succeeded for %s:%d\n",
1409                          hoststr, ntohs(host->port)));
1410                 host->hostFlags |= RESETDONE;
1411             }
1412         }
1413         if (caps.Capabilities_val
1414             && (caps.Capabilities_val[0] & CLIENT_CAPABILITY_ERRORTRANS))
1415             host->hostFlags |= HERRORTRANS;
1416         else
1417             host->hostFlags &= ~(HERRORTRANS);
1418         host->hostFlags |= ALTADDR;     /* host structure initialization complete */
1419         h_Unlock_r(host);
1420     }
1421     if (caps.Capabilities_val)
1422         free(caps.Capabilities_val);
1423     caps.Capabilities_val = NULL;
1424     caps.Capabilities_len = 0;
1425     return host;
1426
1427 }                               /*h_GetHost_r */
1428
1429
1430 static char localcellname[PR_MAXNAMELEN + 1];
1431 char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
1432 int  num_lrealms = -1;
1433
1434 /* not reentrant */
1435 void
1436 h_InitHostPackage()
1437 {
1438     afsconf_GetLocalCell(confDir, localcellname, PR_MAXNAMELEN);
1439     if (num_lrealms == -1) {
1440         int i;
1441         for (i=0; i<AFS_NUM_LREALMS; i++) {
1442             if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
1443                 break;
1444         }
1445
1446         if (i=0) {
1447             ViceLog(0,
1448                     ("afs_krb_get_lrealm failed, using %s.\n",
1449                      localcellname));
1450             strncpy(local_realms[0], localcellname, AFS_REALM_SZ);
1451             num_lrealms = i =1;
1452         } else {
1453             num_lrealms = i;
1454         }
1455
1456         /* initialize the rest of the local realms to nullstring for debugging */
1457         for (; i<AFS_NUM_LREALMS; i++)
1458             local_realms[i][0] = '\0';
1459     }
1460     rxcon_ident_key = rx_KeyCreate((rx_destructor_t) free);
1461     rxcon_client_key = rx_KeyCreate((rx_destructor_t) 0);
1462 #ifdef AFS_PTHREAD_ENV
1463     assert(pthread_mutex_init(&host_glock_mutex, NULL) == 0);
1464 #endif /* AFS_PTHREAD_ENV */
1465 }
1466
1467 static int
1468 MapName_r(char *aname, char *acell, afs_int32 * aval)
1469 {
1470     namelist lnames;
1471     idlist lids;
1472     afs_int32 code;
1473     afs_int32 anamelen, cnamelen;
1474     int foreign = 0;
1475     char *tname;
1476
1477     anamelen = strlen(aname);
1478     if (anamelen >= PR_MAXNAMELEN)
1479         return -1;              /* bad name -- caller interprets this as anonymous, but retries later */
1480
1481     lnames.namelist_len = 1;
1482     lnames.namelist_val = (prname *) aname;     /* don't malloc in the common case */
1483     lids.idlist_len = 0;
1484     lids.idlist_val = NULL;
1485
1486     cnamelen = strlen(acell);
1487     if (cnamelen) {
1488         if (afs_is_foreign_ticket_name(aname, "", acell, localcellname)) {
1489             ViceLog(2,
1490                     ("MapName: cell is foreign.  cell=%s, localcell=%s, localrealms={%s,%s,%s,%s}\n",
1491                     acell, localcellname, local_realms[0],local_realms[1],local_realms[2],local_realms[3]));
1492             if ((anamelen + cnamelen + 1) >= PR_MAXNAMELEN) {
1493                 ViceLog(2,
1494                         ("MapName: Name too long, using AnonymousID for %s@%s\n",
1495                          aname, acell));
1496                 *aval = AnonymousID;
1497                 return 0;
1498             }
1499             foreign = 1;        /* attempt cross-cell authentication */
1500             tname = (char *)malloc(PR_MAXNAMELEN);
1501             if (!tname) {
1502                 ViceLog(0, ("Failed malloc in MapName_r\n"));
1503                 assert(0);
1504             }
1505             strcpy(tname, aname);
1506             tname[anamelen] = '@';
1507             strcpy(tname + anamelen + 1, acell);
1508             lnames.namelist_val = (prname *) tname;
1509         }
1510     }
1511
1512     H_UNLOCK;
1513     code = pr_NameToId(&lnames, &lids);
1514     H_LOCK;
1515     if (code == 0) {
1516         if (lids.idlist_val) {
1517             *aval = lids.idlist_val[0];
1518             if (*aval == AnonymousID) {
1519                 ViceLog(2,
1520                         ("MapName: NameToId on %s returns anonymousID\n",
1521                          lnames.namelist_val));
1522             }
1523             free(lids.idlist_val);      /* return parms are not malloced in stub if server proc aborts */
1524         } else {
1525             ViceLog(0,
1526                     ("MapName: NameToId on '%s' is unknown\n",
1527                      lnames.namelist_val));
1528             code = -1;
1529         }
1530     }
1531
1532     if (foreign) {
1533         free(lnames.namelist_val);      /* We allocated this above, so we must free it now. */
1534     }
1535     return code;
1536 }
1537
1538 /*MapName*/
1539
1540
1541 /* NOTE: this returns the client with a Write lock */
1542 struct client *
1543 h_ID2Client(afs_int32 vid)
1544 {
1545     register struct client *client;
1546     register struct host *host;
1547
1548     H_LOCK;
1549     for (host = hostList; host; host = host->next) {
1550         if (host->hostFlags & HOSTDELETED)
1551             continue;
1552         for (client = host->FirstClient; client; client = client->next) {
1553             if (!client->deleted && client->ViceId == vid) {
1554                 client->refCount++;
1555                 H_UNLOCK;
1556                 ObtainWriteLock(&client->lock);
1557                 H_LOCK;
1558                 client->refCount--;
1559                 H_UNLOCK;
1560                 return client;
1561             }
1562         }
1563     }
1564
1565     H_UNLOCK;
1566     return NULL;
1567 }
1568
1569 /*
1570  * Called by the server main loop.  Returns a h_Held client, which must be
1571  * released later the main loop.  Allocates a client if the matching one
1572  * isn't around. The client is returned with its reference count incremented
1573  * by one. The caller must call h_ReleaseClient_r when finished with
1574  * the client.
1575  */
1576 struct client *
1577 h_FindClient_r(struct rx_connection *tcon)
1578 {
1579     register struct client *client;
1580     register struct host *host;
1581     struct client *oldClient;
1582     afs_int32 viceid;
1583     afs_int32 expTime;
1584     afs_int32 code;
1585     int authClass;
1586 #if (64-MAXKTCNAMELEN)
1587     ticket name length != 64
1588 #endif
1589     char tname[64];
1590     char tinst[64];
1591     char uname[PR_MAXNAMELEN];
1592     char tcell[MAXKTCREALMLEN];
1593     int fail = 0;
1594
1595     client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1596     if (client && !client->deleted) {
1597         client->refCount++;
1598         h_Hold_r(client->host);
1599         if (client->prfail != 2) {      /* Could add shared lock on client here */
1600             /* note that we don't have to lock entry in this path to
1601              * ensure CPS is initialized, since we don't call rx_SetSpecific
1602              * until initialization is done, and we only get here if
1603              * rx_GetSpecific located the client structure.
1604              */
1605             return client;
1606         }
1607         H_UNLOCK;
1608         ObtainWriteLock(&client->lock); /* released at end */
1609         H_LOCK;
1610     } else if (client) {
1611         client->refCount++;
1612     }
1613
1614     authClass = rx_SecurityClassOf((struct rx_connection *)tcon);
1615     ViceLog(5,
1616             ("FindClient: authenticating connection: authClass=%d\n",
1617              authClass));
1618     if (authClass == 1) {
1619         /* A bcrypt tickets, no longer supported */
1620         ViceLog(1, ("FindClient: bcrypt ticket, using AnonymousID\n"));
1621         viceid = AnonymousID;
1622         expTime = 0x7fffffff;
1623     } else if (authClass == 2) {
1624         afs_int32 kvno;
1625
1626         /* kerberos ticket */
1627         code = rxkad_GetServerInfo(tcon, /*level */ 0, &expTime,
1628                                    tname, tinst, tcell, &kvno);
1629         if (code) {
1630             ViceLog(1, ("Failed to get rxkad ticket info\n"));
1631             viceid = AnonymousID;
1632             expTime = 0x7fffffff;
1633         } else {
1634             int ilen = strlen(tinst);
1635             ViceLog(5,
1636                     ("FindClient: rxkad conn: name=%s,inst=%s,cell=%s,exp=%d,kvno=%d\n",
1637                      tname, tinst, tcell, expTime, kvno));
1638             strncpy(uname, tname, sizeof(uname));
1639             if (ilen) {
1640                 if (strlen(uname) + 1 + ilen >= sizeof(uname))
1641                     goto bad_name;
1642                 strcat(uname, ".");
1643                 strcat(uname, tinst);
1644             }
1645             /* translate the name to a vice id */
1646             code = MapName_r(uname, tcell, &viceid);
1647             if (code) {
1648               bad_name:
1649                 ViceLog(1,
1650                         ("failed to map name=%s, cell=%s -> code=%d\n", uname,
1651                          tcell, code));
1652                 fail = 1;
1653                 viceid = AnonymousID;
1654                 expTime = 0x7fffffff;
1655             }
1656         }
1657     } else {
1658         viceid = AnonymousID;   /* unknown security class */
1659         expTime = 0x7fffffff;
1660     }
1661
1662     if (!client) {
1663         host = h_GetHost_r(tcon);       /* Returns it h_Held */
1664
1665     retryfirstclient:
1666         /* First try to find the client structure */
1667         for (client = host->FirstClient; client; client = client->next) {
1668             if (!client->deleted && (client->sid == rxr_CidOf(tcon))
1669                 && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
1670                 if (client->tcon && (client->tcon != tcon)) {
1671                     ViceLog(0,
1672                             ("*** Vid=%d, sid=%x, tcon=%x, Tcon=%x ***\n",
1673                              client->ViceId, client->sid, client->tcon,
1674                              tcon));
1675                     oldClient =
1676                         (struct client *)rx_GetSpecific(client->tcon,
1677                                                         rxcon_client_key);
1678                     if (oldClient) {
1679                         if (oldClient == client)
1680                             rx_SetSpecific(client->tcon, rxcon_client_key,
1681                                            NULL);
1682                         else
1683                             ViceLog(0,
1684                                     ("Client-conn mismatch: CL1=%x, CN=%x, CL2=%x\n",
1685                                      client, client->tcon, oldClient));
1686                     }
1687                     client->tcon = (struct rx_connection *)0;
1688                 }
1689                 client->refCount++;
1690                 H_UNLOCK;
1691                 ObtainWriteLock(&client->lock);
1692                 H_LOCK;
1693                 break;
1694             }
1695         }
1696
1697         /* Still no client structure - get one */
1698         if (!client) {
1699             h_Lock_r(host);
1700             /* Retry to find the client structure */
1701             for (client = host->FirstClient; client; client = client->next) {
1702                 if (!client->deleted && (client->sid == rxr_CidOf(tcon))
1703                     && (client->VenusEpoch == rxr_GetEpoch(tcon))) {
1704                     h_Unlock_r(host);
1705                     goto retryfirstclient;
1706                 }
1707             }
1708             client = GetCE();
1709             ObtainWriteLock(&client->lock);
1710             client->refCount = 1;
1711             client->host = host;
1712             client->next = host->FirstClient;
1713             host->FirstClient = client;
1714 #if FS_STATS_DETAILED
1715             client->InSameNetwork = host->InSameNetwork;
1716 #endif /* FS_STATS_DETAILED */
1717             client->ViceId = viceid;
1718             client->expTime = expTime;  /* rx only */
1719             client->authClass = authClass;      /* rx only */
1720             client->sid = rxr_CidOf(tcon);
1721             client->VenusEpoch = rxr_GetEpoch(tcon);
1722             client->CPS.prlist_val = 0;
1723             client->CPS.prlist_len = 0;
1724             h_Unlock_r(host);
1725             CurrentConnections++;       /* increment number of connections */
1726         }
1727     }
1728     client->prfail = fail;
1729
1730     if (!(client->CPS.prlist_val) || (viceid != client->ViceId)) {
1731         if (client->CPS.prlist_val && (client->ViceId != ANONYMOUSID)) {
1732             free(client->CPS.prlist_val);
1733         }
1734         client->CPS.prlist_val = NULL;
1735         client->CPS.prlist_len = 0;
1736         client->ViceId = viceid;
1737         client->expTime = expTime;
1738
1739         if (viceid == ANONYMOUSID) {
1740             client->CPS.prlist_len = AnonCPS.prlist_len;
1741             client->CPS.prlist_val = AnonCPS.prlist_val;
1742         } else {
1743             H_UNLOCK;
1744             code = pr_GetCPS(viceid, &client->CPS);
1745             H_LOCK;
1746             if (code) {
1747                 char hoststr[16];
1748                 ViceLog(0,
1749                         ("pr_GetCPS failed(%d) for user %d, host %s:%d\n",
1750                          code, viceid, afs_inet_ntoa_r(client->host->host,
1751                                                        hoststr),
1752                          ntohs(client->host->port)));
1753
1754                 /* Although ubik_Call (called by pr_GetCPS) traverses thru
1755                  * all protection servers and reevaluates things if no
1756                  * sync server or quorum is found we could still end up
1757                  * with one of these errors. In such case we would like to
1758                  * reevaluate the rpc call to find if there's cps for this
1759                  * guy. We treat other errors (except network failures
1760                  * ones - i.e. code < 0) as an indication that there is no
1761                  * CPS for this host.  Ideally we could like to deal this
1762                  * problem the other way around (i.e.  if code == NOCPS
1763                  * ignore else retry next time) but the problem is that
1764                  * there're other errors (i.e.  EPERM) for which we don't
1765                  * want to retry and we don't know the whole code list!
1766                  */
1767                 if (code < 0 || code == UNOQUORUM || code == UNOTSYNC)
1768                     client->prfail = 1;
1769             }
1770         }
1771         /* the disabling of system:administrators is so iffy and has so many
1772          * possible failure modes that we will disable it again */
1773         /* Turn off System:Administrator for safety  
1774          * if (AL_IsAMember(SystemId, client->CPS) == 0)
1775          * assert(AL_DisableGroup(SystemId, client->CPS) == 0); */
1776     }
1777
1778     /* Now, tcon may already be set to a rock, since we blocked with no host
1779      * or client locks set above in pr_GetCPS (XXXX some locking is probably
1780      * required).  So, before setting the RPC's rock, we should disconnect
1781      * the RPC from the other client structure's rock.
1782      */
1783     oldClient = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1784     if (oldClient && oldClient->tcon == tcon) {
1785         char hoststr[16];
1786         oldClient->tcon = (struct rx_connection *)0;
1787         ViceLog(0, ("FindClient: client %x(%x) already had conn %x (host %s:%d), stolen by client %x(%x)\n", 
1788                     oldClient, oldClient->sid, tcon, 
1789                     afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr),
1790                     ntohs(rxr_PortOf(tcon)),
1791                     client, client->sid));
1792         /* rx_SetSpecific will be done immediately below */
1793     }
1794     client->tcon = tcon;
1795     rx_SetSpecific(tcon, rxcon_client_key, client);
1796     ReleaseWriteLock(&client->lock);
1797
1798     return client;
1799
1800 }                               /*h_FindClient_r */
1801
1802 int
1803 h_ReleaseClient_r(struct client *client)
1804 {
1805     assert(client->refCount > 0);
1806     client->refCount--;
1807     return 0;
1808 }
1809
1810
1811 /*
1812  * Sigh:  this one is used to get the client AGAIN within the individual
1813  * server routines.  This does not bother h_Holding the host, since
1814  * this is assumed already have been done by the server main loop.
1815  * It does check tokens, since only the server routines can return the
1816  * VICETOKENDEAD error code
1817  */
1818 int
1819 GetClient(struct rx_connection *tcon, struct client **cp)
1820 {
1821     register struct client *client;
1822
1823     H_LOCK;
1824     *cp = client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key);
1825     if (client == NULL || client->tcon == NULL) {
1826         ViceLog(0,
1827                 ("GetClient: no client in conn %x (host %x:%d), VBUSYING\n",
1828                  tcon, rxr_HostOf(tcon),ntohs(rxr_PortOf(tcon))));
1829         H_UNLOCK;
1830         return VBUSY;
1831     }
1832     if (rxr_CidOf(client->tcon) != client->sid) {
1833         ViceLog(0,
1834                 ("GetClient: tcon %x tcon sid %d client sid %d\n",
1835                  client->tcon, rxr_CidOf(client->tcon), client->sid));
1836         H_UNLOCK;
1837         return VBUSY;
1838     }
1839     if (!(client && client->tcon && rxr_CidOf(client->tcon) == client->sid)) {
1840         if (!client)
1841             ViceLog(0, ("GetClient: no client in conn %x\n", tcon));
1842         else
1843             ViceLog(0,
1844                     ("GetClient: tcon %x tcon sid %d client sid %d\n",
1845                      client->tcon, client->tcon ? rxr_CidOf(client->tcon)
1846                      : -1, client->sid));
1847         assert(0);
1848     }
1849     if (client && client->LastCall > client->expTime && client->expTime) {
1850         char hoststr[16];
1851         ViceLog(1,
1852                 ("Token for %s at %s:%d expired %d\n", h_UserName(client),
1853                  afs_inet_ntoa_r(client->host->host, hoststr),
1854                  ntohs(client->host->port), client->expTime));
1855         H_UNLOCK;
1856         return VICETOKENDEAD;
1857     }
1858
1859     H_UNLOCK;
1860     return 0;
1861
1862 }                               /*GetClient */
1863
1864
1865 /* Client user name for short term use.  Note that this is NOT inexpensive */
1866 char *
1867 h_UserName(struct client *client)
1868 {
1869     static char User[PR_MAXNAMELEN + 1];
1870     namelist lnames;
1871     idlist lids;
1872
1873     lids.idlist_len = 1;
1874     lids.idlist_val = (afs_int32 *) malloc(1 * sizeof(afs_int32));
1875     if (!lids.idlist_val) {
1876         ViceLog(0, ("Failed malloc in h_UserName\n"));
1877         assert(0);
1878     }
1879     lnames.namelist_len = 0;
1880     lnames.namelist_val = (prname *) 0;
1881     lids.idlist_val[0] = client->ViceId;
1882     if (pr_IdToName(&lids, &lnames)) {
1883         /* We need to free id we alloced above! */
1884         free(lids.idlist_val);
1885         return "*UNKNOWN USER NAME*";
1886     }
1887     strncpy(User, lnames.namelist_val[0], PR_MAXNAMELEN);
1888     free(lids.idlist_val);
1889     free(lnames.namelist_val);
1890     return User;
1891
1892 }                               /*h_UserName */
1893
1894
1895 void
1896 h_PrintStats()
1897 {
1898     ViceLog(0,
1899             ("Total Client entries = %d, blocks = %d; Host entries = %d, blocks = %d\n",
1900              CEs, CEBlocks, HTs, HTBlocks));
1901
1902 }                               /*h_PrintStats */
1903
1904
1905 static int
1906 h_PrintClient(register struct host *host, int held, StreamHandle_t * file)
1907 {
1908     register struct client *client;
1909     int i;
1910     char tmpStr[256];
1911     char tbuffer[32];
1912     char hoststr[16];
1913
1914     H_LOCK;
1915     if (host->hostFlags & HOSTDELETED) {
1916         H_UNLOCK;
1917         return held;
1918     }
1919     (void)afs_snprintf(tmpStr, sizeof tmpStr,
1920                        "Host %s:%d down = %d, LastCall %s",
1921                        afs_inet_ntoa_r(host->host, hoststr),
1922                        ntohs(host->port), (host->hostFlags & VENUSDOWN),
1923                        afs_ctime((time_t *) & host->LastCall, tbuffer,
1924                                  sizeof(tbuffer)));
1925     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1926     for (client = host->FirstClient; client; client = client->next) {
1927         if (!client->deleted) {
1928             if (client->tcon) {
1929                 (void)afs_snprintf(tmpStr, sizeof tmpStr,
1930                                    "    user id=%d,  name=%s, sl=%s till %s",
1931                                    client->ViceId, h_UserName(client),
1932                                    client->
1933                                    authClass ? "Authenticated" :
1934                                    "Not authenticated",
1935                                    client->
1936                                    authClass ? afs_ctime((time_t *) & client->
1937                                                          expTime, tbuffer,
1938                                                          sizeof(tbuffer))
1939                                    : "No Limit\n");
1940                 (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1941             } else {
1942                 (void)afs_snprintf(tmpStr, sizeof tmpStr,
1943                                    "    user=%s, no current server connection\n",
1944                                    h_UserName(client));
1945                 (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1946             }
1947             (void)afs_snprintf(tmpStr, sizeof tmpStr, "      CPS-%d is [",
1948                                client->CPS.prlist_len);
1949             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1950             if (client->CPS.prlist_val) {
1951                 for (i = 0; i > client->CPS.prlist_len; i++) {
1952                     (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
1953                                        client->CPS.prlist_val[i]);
1954                     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1955                 }
1956             }
1957             sprintf(tmpStr, "]\n");
1958             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1959         }
1960     }
1961     H_UNLOCK;
1962     return held;
1963
1964 }                               /*h_PrintClient */
1965
1966
1967
1968 /*
1969  * Print a list of clients, with last security level and token value seen,
1970  * if known
1971  */
1972 void
1973 h_PrintClients()
1974 {
1975     time_t now;
1976     char tmpStr[256];
1977     char tbuffer[32];
1978
1979     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_CLNTDUMP_FILEPATH, "w");
1980
1981     if (file == NULL) {
1982         ViceLog(0,
1983                 ("Couldn't create client dump file %s\n",
1984                  AFSDIR_SERVER_CLNTDUMP_FILEPATH));
1985         return;
1986     }
1987     now = FT_ApproxTime();
1988     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active users at %s\n",
1989                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
1990     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
1991     h_Enumerate(h_PrintClient, (char *)file);
1992     STREAM_REALLYCLOSE(file);
1993     ViceLog(0, ("Created client dump %s\n", AFSDIR_SERVER_CLNTDUMP_FILEPATH));
1994 }
1995
1996
1997
1998
1999 static int
2000 h_DumpHost(register struct host *host, int held, StreamHandle_t * file)
2001 {
2002     int i;
2003     char tmpStr[256];
2004     char hoststr[16];
2005
2006     H_LOCK;
2007     (void)afs_snprintf(tmpStr, sizeof tmpStr,
2008                        "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 [",
2009                        afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), host->index,
2010                        host->cblist, CheckLock(&host->lock), host->LastCall,
2011                        host->ActiveCall, (host->hostFlags & VENUSDOWN),
2012                        host->hostFlags & HOSTDELETED, host->Console,
2013                        host->hostFlags & CLIENTDELETED, host->hcpsfailed,
2014                        host->cpsCall);
2015     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2016     if (host->hcps.prlist_val)
2017         for (i = 0; i < host->hcps.prlist_len; i++) {
2018             (void)afs_snprintf(tmpStr, sizeof tmpStr, " %d",
2019                                host->hcps.prlist_val[i]);
2020             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2021         }
2022     sprintf(tmpStr, "] [");
2023     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2024     if (host->interface)
2025         for (i = 0; i < host->interface->numberOfInterfaces; i++) {
2026             char hoststr[16];
2027             sprintf(tmpStr, " %s:%d", 
2028                      afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2029                      ntohs(host->interface->interface[i].port));
2030             (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2031         }
2032     sprintf(tmpStr, "] holds: ");
2033     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2034
2035     for (i = 0; i < h_maxSlots; i++) {
2036         sprintf(tmpStr, "%04x", host->holds[i]);
2037         (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2038     }
2039     sprintf(tmpStr, " slot/bit: %d/%d\n", h_holdSlot(), h_holdbit());
2040     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2041
2042     H_UNLOCK;
2043     return held;
2044
2045 }                               /*h_DumpHost */
2046
2047
2048 void
2049 h_DumpHosts()
2050 {
2051     time_t now;
2052     StreamHandle_t *file = STREAM_OPEN(AFSDIR_SERVER_HOSTDUMP_FILEPATH, "w");
2053     char tmpStr[256];
2054     char tbuffer[32];
2055
2056     if (file == NULL) {
2057         ViceLog(0,
2058                 ("Couldn't create host dump file %s\n",
2059                  AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2060         return;
2061     }
2062     now = FT_ApproxTime();
2063     (void)afs_snprintf(tmpStr, sizeof tmpStr, "List of active hosts at %s\n",
2064                        afs_ctime(&now, tbuffer, sizeof(tbuffer)));
2065     (void)STREAM_WRITE(tmpStr, strlen(tmpStr), 1, file);
2066     h_Enumerate(h_DumpHost, (char *)file);
2067     STREAM_REALLYCLOSE(file);
2068     ViceLog(0, ("Created host dump %s\n", AFSDIR_SERVER_HOSTDUMP_FILEPATH));
2069
2070 }                               /*h_DumpHosts */
2071
2072
2073 /*
2074  * This counts the number of workstations, the number of active workstations,
2075  * and the number of workstations declared "down" (i.e. not heard from
2076  * recently).  An active workstation has received a call since the cutoff
2077  * time argument passed.
2078  */
2079 void
2080 h_GetWorkStats(int *nump, int *activep, int *delp, afs_int32 cutofftime)
2081 {
2082     register struct host *host;
2083     register int num = 0, active = 0, del = 0;
2084
2085     H_LOCK;
2086     for (host = hostList; host; host = host->next) {
2087         if (!(host->hostFlags & HOSTDELETED)) {
2088             num++;
2089             if (host->ActiveCall > cutofftime)
2090                 active++;
2091             if (host->hostFlags & VENUSDOWN)
2092                 del++;
2093         }
2094     }
2095     H_UNLOCK;
2096     if (nump)
2097         *nump = num;
2098     if (activep)
2099         *activep = active;
2100     if (delp)
2101         *delp = del;
2102
2103 }                               /*h_GetWorkStats */
2104
2105
2106 /*------------------------------------------------------------------------
2107  * PRIVATE h_ClassifyAddress
2108  *
2109  * Description:
2110  *      Given a target IP address and a candidate IP address (both
2111  *      in host byte order), classify the candidate into one of three
2112  *      buckets in relation to the target by bumping the counters passed
2113  *      in as parameters.
2114  *
2115  * Arguments:
2116  *      a_targetAddr       : Target address.
2117  *      a_candAddr         : Candidate address.
2118  *      a_sameNetOrSubnetP : Ptr to counter to bump when the two
2119  *                           addresses are either in the same network
2120  *                           or the same subnet.
2121  *      a_diffSubnetP      : ...when the candidate is in a different
2122  *                           subnet.
2123  *      a_diffNetworkP     : ...when the candidate is in a different
2124  *                           network.
2125  *
2126  * Returns:
2127  *      Nothing.
2128  *
2129  * Environment:
2130  *      The target and candidate addresses are both in host byte
2131  *      order, NOT network byte order, when passed in.
2132  *
2133  * Side Effects:
2134  *      As advertised.
2135  *------------------------------------------------------------------------*/
2136
2137 static void
2138 h_ClassifyAddress(afs_uint32 a_targetAddr, afs_uint32 a_candAddr,
2139                   afs_int32 * a_sameNetOrSubnetP, afs_int32 * a_diffSubnetP,
2140                   afs_int32 * a_diffNetworkP)
2141 {                               /*h_ClassifyAddress */
2142
2143     afs_uint32 targetNet;
2144     afs_uint32 targetSubnet;
2145     afs_uint32 candNet;
2146     afs_uint32 candSubnet;
2147
2148     /*
2149      * Put bad values into the subnet info to start with.
2150      */
2151     targetSubnet = (afs_uint32) 0;
2152     candSubnet = (afs_uint32) 0;
2153
2154     /*
2155      * Pull out the network and subnetwork numbers from the target
2156      * and candidate addresses.  We can short-circuit this whole
2157      * affair if the target and candidate addresses are not of the
2158      * same class.
2159      */
2160     if (IN_CLASSA(a_targetAddr)) {
2161         if (!(IN_CLASSA(a_candAddr))) {
2162             (*a_diffNetworkP)++;
2163             return;
2164         }
2165         targetNet = a_targetAddr & IN_CLASSA_NET;
2166         candNet = a_candAddr & IN_CLASSA_NET;
2167         if (IN_SUBNETA(a_targetAddr))
2168             targetSubnet = a_targetAddr & IN_CLASSA_SUBNET;
2169         if (IN_SUBNETA(a_candAddr))
2170             candSubnet = a_candAddr & IN_CLASSA_SUBNET;
2171     } else if (IN_CLASSB(a_targetAddr)) {
2172         if (!(IN_CLASSB(a_candAddr))) {
2173             (*a_diffNetworkP)++;
2174             return;
2175         }
2176         targetNet = a_targetAddr & IN_CLASSB_NET;
2177         candNet = a_candAddr & IN_CLASSB_NET;
2178         if (IN_SUBNETB(a_targetAddr))
2179             targetSubnet = a_targetAddr & IN_CLASSB_SUBNET;
2180         if (IN_SUBNETB(a_candAddr))
2181             candSubnet = a_candAddr & IN_CLASSB_SUBNET;
2182     } /*Class B target */
2183     else if (IN_CLASSC(a_targetAddr)) {
2184         if (!(IN_CLASSC(a_candAddr))) {
2185             (*a_diffNetworkP)++;
2186             return;
2187         }
2188         targetNet = a_targetAddr & IN_CLASSC_NET;
2189         candNet = a_candAddr & IN_CLASSC_NET;
2190
2191         /*
2192          * Note that class C addresses can't have subnets,
2193          * so we leave the defaults untouched.
2194          */
2195     } /*Class C target */
2196     else {
2197         targetNet = a_targetAddr;
2198         candNet = a_candAddr;
2199     }                           /*Class D address */
2200
2201     /*
2202      * Now, simply compare the extracted net and subnet values for
2203      * the two addresses (which at this point are known to be of the
2204      * same class)
2205      */
2206     if (targetNet == candNet) {
2207         if (targetSubnet == candSubnet)
2208             (*a_sameNetOrSubnetP)++;
2209         else
2210             (*a_diffSubnetP)++;
2211     } else
2212         (*a_diffNetworkP)++;
2213
2214 }                               /*h_ClassifyAddress */
2215
2216
2217 /*------------------------------------------------------------------------
2218  * EXPORTED h_GetHostNetStats
2219  *
2220  * Description:
2221  *      Iterate through the host table, and classify each (non-deleted)
2222  *      host entry into ``proximity'' categories (same net or subnet,
2223  *      different subnet, different network).
2224  *
2225  * Arguments:
2226  *      a_numHostsP        : Set to total number of (non-deleted) hosts.
2227  *      a_sameNetOrSubnetP : Set to # hosts on same net/subnet as server.
2228  *      a_diffSubnetP      : Set to # hosts on diff subnet as server.
2229  *      a_diffNetworkP     : Set to # hosts on diff network as server.
2230  *
2231  * Returns:
2232  *      Nothing.
2233  *
2234  * Environment:
2235  *      We only count non-deleted hosts.  The storage pointed to by our
2236  *      parameters is zeroed upon entry.
2237  *
2238  * Side Effects:
2239  *      As advertised.
2240  *------------------------------------------------------------------------*/
2241
2242 void
2243 h_GetHostNetStats(afs_int32 * a_numHostsP, afs_int32 * a_sameNetOrSubnetP,
2244                   afs_int32 * a_diffSubnetP, afs_int32 * a_diffNetworkP)
2245 {                               /*h_GetHostNetStats */
2246
2247     register struct host *hostP;        /*Ptr to current host entry */
2248     register afs_uint32 currAddr_HBO;   /*Curr host addr, host byte order */
2249
2250     /*
2251      * Clear out the storage pointed to by our parameters.
2252      */
2253     *a_numHostsP = (afs_int32) 0;
2254     *a_sameNetOrSubnetP = (afs_int32) 0;
2255     *a_diffSubnetP = (afs_int32) 0;
2256     *a_diffNetworkP = (afs_int32) 0;
2257
2258     H_LOCK;
2259     for (hostP = hostList; hostP; hostP = hostP->next) {
2260         if (!(hostP->hostFlags & HOSTDELETED)) {
2261             /*
2262              * Bump the number of undeleted host entries found.
2263              * In classifying the current entry's address, make
2264              * sure to first convert to host byte order.
2265              */
2266             (*a_numHostsP)++;
2267             currAddr_HBO = (afs_uint32) ntohl(hostP->host);
2268             h_ClassifyAddress(FS_HostAddr_HBO, currAddr_HBO,
2269                               a_sameNetOrSubnetP, a_diffSubnetP,
2270                               a_diffNetworkP);
2271         }                       /*Only look at non-deleted hosts */
2272     }                           /*For each host record hashed to this index */
2273     H_UNLOCK;
2274 }                               /*h_GetHostNetStats */
2275
2276 static afs_uint32 checktime;
2277 static afs_uint32 clientdeletetime;
2278 static struct AFSFid zerofid;
2279
2280
2281 /*
2282  * XXXX: This routine could use Multi-Rx to avoid serializing the timeouts.
2283  * Since it can serialize them, and pile up, it should be a separate LWP
2284  * from other events.
2285  */
2286 int
2287 CheckHost(register struct host *host, int held)
2288 {
2289     register struct client *client;
2290     struct rx_connection *cb_conn = NULL;
2291     int code;
2292
2293     /* Host is held by h_Enumerate */
2294     H_LOCK;
2295     for (client = host->FirstClient; client; client = client->next) {
2296         if (client->refCount == 0 && client->LastCall < clientdeletetime) {
2297             client->deleted = 1;
2298             host->hostFlags |= CLIENTDELETED;
2299         }
2300     }
2301     if (host->LastCall < checktime) {
2302         h_Lock_r(host);
2303         if (!(host->hostFlags & HOSTDELETED)) {
2304             cb_conn = host->callback_rxcon;
2305             rx_GetConnection(cb_conn);
2306             if (host->LastCall < clientdeletetime) {
2307                 host->hostFlags |= HOSTDELETED;
2308                 if (!(host->hostFlags & VENUSDOWN)) {
2309                     host->hostFlags &= ~ALTADDR;        /* alternate address invalid */
2310                     if (host->interface) {
2311                         H_UNLOCK;
2312                         code =
2313                             RXAFSCB_InitCallBackState3(cb_conn,
2314                                                        &FS_HostUUID);
2315                         H_LOCK;
2316                     } else {
2317                         H_UNLOCK;
2318                         code =
2319                             RXAFSCB_InitCallBackState(cb_conn);
2320                         H_LOCK;
2321                     }
2322                     host->hostFlags |= ALTADDR; /* alternate addresses valid */
2323                     if (code) {
2324                         char hoststr[16];
2325                         (void)afs_inet_ntoa_r(host->host, hoststr);
2326                         ViceLog(0,
2327                                 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
2328                                  hoststr, ntohs(host->port)));
2329                         host->hostFlags |= VENUSDOWN;
2330                     }
2331                     /* Note:  it's safe to delete hosts even if they have call
2332                      * back state, because break delayed callbacks (called when a
2333                      * message is received from the workstation) will always send a 
2334                      * break all call backs to the workstation if there is no
2335                      *callback.
2336                      */
2337                 }
2338             } else {
2339                 if (!(host->hostFlags & VENUSDOWN) && host->cblist) {
2340                     if (host->interface) {
2341                         afsUUID uuid = host->interface->uuid;
2342                         H_UNLOCK;
2343                         code = RXAFSCB_ProbeUuid(cb_conn, &uuid);
2344                         H_LOCK;
2345                         if (code) {
2346                             if (MultiProbeAlternateAddress_r(host)) {
2347                                 char hoststr[16];
2348                                 (void)afs_inet_ntoa_r(host->host, hoststr);
2349                                 ViceLog(0,
2350                                         ("ProbeUuid failed for host %s:%d\n",
2351                                          hoststr, ntohs(host->port)));
2352                                 host->hostFlags |= VENUSDOWN;
2353                             }
2354                         }
2355                     } else {
2356                         H_UNLOCK;
2357                         code = RXAFSCB_Probe(cb_conn);
2358                         H_LOCK;
2359                         if (code) {
2360                             char hoststr[16];
2361                             (void)afs_inet_ntoa_r(host->host, hoststr);
2362                             ViceLog(0,
2363                                     ("Probe failed for host %s:%d\n", hoststr,
2364                                      ntohs(host->port)));
2365                             host->hostFlags |= VENUSDOWN;
2366                         }
2367                     }
2368                 }
2369             }
2370             H_UNLOCK;
2371             rx_PutConnection(cb_conn);
2372             cb_conn=NULL;
2373             H_LOCK;
2374         }
2375         h_Unlock_r(host);
2376     }
2377     H_UNLOCK;
2378     return held;
2379
2380 }                               /*CheckHost */
2381
2382
2383 /*
2384  * Set VenusDown for any hosts that have not had a call in 15 minutes and
2385  * don't respond to a probe.  Note that VenusDown can only be cleared if
2386  * a message is received from the host (see ServerLWP in file.c).
2387  * Delete hosts that have not had any calls in 1 hour, clients that
2388  * have not had any calls in 15 minutes.
2389  *
2390  * This routine is called roughly every 5 minutes.
2391  */
2392 void
2393 h_CheckHosts()
2394 {
2395     afs_uint32 now = FT_ApproxTime();
2396
2397     memset((char *)&zerofid, 0, sizeof(zerofid));
2398     /*
2399      * Send a probe to the workstation if it hasn't been heard from in
2400      * 15 minutes
2401      */
2402     checktime = now - 15 * 60;
2403     clientdeletetime = now - 120 * 60;  /* 2 hours ago */
2404     h_Enumerate(CheckHost, NULL);
2405
2406 }                               /*h_CheckHosts */
2407
2408 /*
2409  * This is called with host locked and held. At this point, the
2410  * hostHashTable should not have any entries for the alternate
2411  * interfaces. This function has to insert these entries in the
2412  * hostHashTable.
2413  *
2414  * The addresses in the interfaceAddr list are in host byte order.
2415  */
2416 int
2417 initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf)
2418 {
2419     int i, j;
2420     int number, count;
2421     afs_uint32 myAddr;
2422     afs_uint16 myPort;
2423     int found;
2424     struct Interface *interface;
2425
2426     assert(host);
2427     assert(interf);
2428
2429     ViceLog(125,
2430             ("initInterfaceAddr : host %x numAddr %d\n", host->host,
2431              interf->numberOfInterfaces));
2432
2433     number = interf->numberOfInterfaces;
2434     myAddr = host->host;        /* current interface address */
2435     myPort = host->port;        /* current port */
2436
2437     /* validation checks */
2438     if (number < 0 || number > AFS_MAX_INTERFACE_ADDR) {
2439         ViceLog(0,
2440                 ("Number of alternate addresses returned is %d\n", number));
2441         return -1;
2442     }
2443
2444     /*
2445      * Convert IP addresses to network byte order, and remove for
2446      * duplicate IP addresses from the interface list.
2447      */
2448     for (i = 0, count = 0, found = 0; i < number; i++) {
2449         interf->addr_in[i] = htonl(interf->addr_in[i]);
2450         for (j = 0; j < count; j++) {
2451             if (interf->addr_in[j] == interf->addr_in[i])
2452                 break;
2453         }
2454         if (j == count) {
2455             interf->addr_in[count] = interf->addr_in[i];
2456             if (interf->addr_in[count] == myAddr)
2457                 found = 1;
2458             count++;
2459         }
2460     }
2461
2462     /*
2463      * Allocate and initialize an interface structure for this host.
2464      */
2465     if (found) {
2466         interface = (struct Interface *)
2467             malloc(sizeof(struct Interface) +
2468                    (sizeof(struct AddrPort) * (count - 1)));
2469         if (!interface) {
2470             ViceLog(0, ("Failed malloc in initInterfaceAddr_r\n"));
2471             assert(0);
2472         }
2473         interface->numberOfInterfaces = count;
2474     } else {
2475         interface = (struct Interface *)
2476             malloc(sizeof(struct Interface) + (sizeof(struct AddrPort) * count));
2477         assert(interface);
2478         interface->numberOfInterfaces = count + 1;
2479         interface->interface[count].addr = myAddr;
2480         interface->interface[count].port = myPort;
2481     }
2482     interface->uuid = interf->uuid;
2483     for (i = 0; i < count; i++) {
2484         interface->interface[i].addr = interf->addr_in[i];
2485         /* We store the port as 7001 because the addresses reported by 
2486          * TellMeAboutYourself and WhoAreYou RPCs are only valid if they
2487          * are coming from fully connected hosts (no NAT/PATs)
2488          */
2489         interface->interface[i].port = htons(7001);
2490     }
2491
2492     assert(!host->interface);
2493     host->interface = interface;
2494
2495     for (i = 0; i < host->interface->numberOfInterfaces; i++) {
2496         char hoststr[16];
2497         ViceLog(125, ("--- alt address %s:%d\n", 
2498                        afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2499                        ntohs(host->interface->interface[i].port)));
2500     }
2501
2502     return 0;
2503 }
2504
2505 /* deleted a HashChain structure for this address and host */
2506 /* returns 1 on success */
2507 int
2508 hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host)
2509 {
2510     int flag;
2511     register struct h_hashChain **hp, *th;
2512
2513     for (hp = &hostHashTable[h_HashIndex(addr)]; (th = *hp);) {
2514         assert(th->hostPtr);
2515         if (th->hostPtr == host && th->addr == addr && th->port == port) {
2516             *hp = th->next;
2517             free(th);
2518             flag = 1;
2519             break;
2520         } else {
2521             hp = &th->next;
2522         }
2523     }
2524     return flag;
2525 }
2526
2527
2528 /*
2529 ** prints out all alternate interface address for the host. The 'level'
2530 ** parameter indicates what level of debugging sets this output
2531 */
2532 void
2533 printInterfaceAddr(struct host *host, int level)
2534 {
2535     int i, number;
2536     char hoststr[16];
2537
2538     if (host->interface) {
2539         /* check alternate addresses */
2540         number = host->interface->numberOfInterfaces;
2541         assert(number > 0);
2542         for (i = 0; i < number; i++)
2543             ViceLog(level, ("%s:%d ", afs_inet_ntoa_r(host->interface->interface[i].addr, hoststr),
2544                              ntohs(host->interface->interface[i].port)));
2545     }
2546     ViceLog(level, ("\n"));
2547 }