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