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