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