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