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