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