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