2 * Copyright 2000, International Business Machines Corporation and others.
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
9 * Portions Copyright (c) 2006 Sine Nomine Associates
12 #include <afsconfig.h>
13 #include <afs/param.h>
20 #ifdef HAVE_SYS_FILE_H
24 #include <afs/afsint.h>
25 #define FSINT_COMMON_XG
26 #include <afs/afscbint.h>
27 #include <afs/rxgen_consts.h>
29 #include <afs/errors.h>
30 #include <afs/ihandle.h>
32 #include <afs/ptclient.h>
33 #include <afs/ptuser.h>
34 #include <afs/prs_fs.h>
36 #include <afs/afsutil.h>
37 #include <afs/com_err.h>
39 #include <afs/cellconfig.h>
40 #include "viced_prototypes.h"
44 #ifdef AFS_DEMAND_ATTACH_FS
45 #include "../util/afsutil_prototypes.h"
46 #include "serialize_state.h"
47 #endif /* AFS_DEMAND_ATTACH_FS */
49 pthread_mutex_t host_glock_mutex
;
52 extern int CurrentConnections
;
54 extern int AnonymousID
;
55 extern prlist AnonCPS
;
56 extern struct afsconf_dir
*confDir
; /* config dir object */
57 extern int lwps
; /* the max number of server threads */
58 extern afsUUID FS_HostUUID
;
59 extern char *FS_configPath
;
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 */
70 static struct rx_securityClass
*sc
= NULL
;
71 static int h_quota_limit
;
73 /* arguments for PerHost_EnumerateClient enumeration */
74 struct enumclient_args
{
76 int (*proc
)(struct client
*client
, void *rock
);
80 static void h_SetupCallbackConn_r(struct host
* host
);
81 static int h_threadquota(int);
82 static int initInterfaceAddr_r(struct host
*, struct interfaceAddr
*);
84 #define CESPERBLOCK 73
85 struct CEBlock
{ /* block of CESPERBLOCK file entries */
86 struct client entry
[CESPERBLOCK
];
89 void h_TossStuff_r(struct host
*host
);
92 * Make sure the subnet macros have been defined.
95 #define IN_SUBNETA(i) ((((afs_int32)(i))&0x80800000)==0x00800000)
98 #ifndef IN_CLASSA_SUBNET
99 #define IN_CLASSA_SUBNET 0xffff0000
103 #define IN_SUBNETB(i) ((((afs_int32)(i))&0xc0008000)==0x80008000)
106 #ifndef IN_CLASSB_SUBNET
107 #define IN_CLASSB_SUBNET 0xffffff00
110 #define hostBusyFlags(hf) \
111 ((hf) & (HWHO_INPROGRESS | HCPS_INPROGRESS | HCPS_WAITING) \
112 || !((hf) & ALTADDR))
114 /* get a new block of CEs and chain it on CEFree */
118 struct CEBlock
*block
;
121 block
= malloc(sizeof(struct CEBlock
));
123 ViceLog(0, ("Failed malloc in GetCEBlock\n"));
124 ShutDownAndCore(PANIC
);
127 for (i
= 0; i
< (CESPERBLOCK
- 1); i
++) {
128 Lock_Init(&block
->entry
[i
].lock
);
129 block
->entry
[i
].z
.next
= &(block
->entry
[i
+ 1]);
131 block
->entry
[CESPERBLOCK
- 1].z
.next
= 0;
132 Lock_Init(&block
->entry
[CESPERBLOCK
- 1].lock
);
133 CEFree
= (struct client
*)block
;
139 /* get the next available CE */
140 static struct client
*
143 struct client
*entry
;
148 ViceLog(0, ("CEFree NULL in GetCE\n"));
149 ShutDownAndCore(PANIC
);
153 CEFree
= entry
->z
.next
;
155 memset(&entry
->z
, 0, sizeof(struct client_to_zero
));
161 /* return an entry to the free list */
163 FreeCE(struct client
*entry
)
165 entry
->z
.VenusEpoch
= 0;
167 entry
->z
.next
= CEFree
;
174 * The HTs and HTBlocks variables were formerly static, but they are
175 * now referenced elsewhere in the FileServer.
177 int HTs
= 0; /* active file entries */
178 int HTBlocks
= 0; /* number of blocks of HTs */
179 static struct host
*HTFree
= 0; /* first free file entry */
182 * Hash tables of host pointers. We need two tables, one
183 * to map IP addresses onto host pointers, and another
184 * to map host UUIDs onto host pointers.
186 static struct h_AddrHashChain
*hostAddrHashTable
[h_HASHENTRIES
];
187 static struct h_UuidHashChain
*hostUuidHashTable
[h_HASHENTRIES
];
188 #define h_HashIndex(hostip) (ntohl(hostip) & (h_HASHENTRIES-1))
189 #define h_UuidHashIndex(uuidp) (((int)(afs_uuid_hash(uuidp))) & (h_HASHENTRIES-1))
191 struct HTBlock
{ /* block of HTSPERBLOCK file entries */
192 struct host entry
[h_HTSPERBLOCK
];
196 /* get a new block of HTs and chain it on HTFree */
200 struct HTBlock
*block
;
202 static int index
= 0;
204 if (HTBlocks
== h_MAXHOSTTABLES
) {
205 ViceLog(0, ("h_MAXHOSTTABLES reached\n"));
209 block
= malloc(sizeof(struct HTBlock
));
211 ViceLog(0, ("Failed malloc in GetHTBlock\n"));
212 ShutDownAndCore(PANIC
);
214 for (i
= 0; i
< (h_HTSPERBLOCK
); i
++)
215 opr_cv_init(&block
->entry
[i
].cond
);
216 for (i
= 0; i
< (h_HTSPERBLOCK
); i
++)
217 Lock_Init(&block
->entry
[i
].lock
);
218 for (i
= 0; i
< (h_HTSPERBLOCK
- 1); i
++)
219 block
->entry
[i
].z
.next
= &(block
->entry
[i
+ 1]);
220 for (i
= 0; i
< (h_HTSPERBLOCK
); i
++)
221 block
->entry
[i
].index
= index
++;
222 block
->entry
[h_HTSPERBLOCK
- 1].z
.next
= 0;
223 HTFree
= (struct host
*)block
;
224 hosttableptrs
[HTBlocks
++] = block
->entry
;
229 /* get the next available HT */
240 HTFree
= entry
->z
.next
;
242 memset(&entry
->z
, 0, sizeof(struct host_to_zero
));
248 /* return an entry to the free list */
250 FreeHT(struct host
*entry
)
252 entry
->z
.next
= HTFree
;
259 hpr_Initialize(struct ubik_client
**uclient
)
261 afs_int32 code
, code2
;
262 struct rx_connection
*serverconns
[MAXSERVERS
];
263 struct rx_securityClass
*sc
;
264 struct afsconf_dir
*tdir
;
266 struct afsconf_cell info
;
270 tdir
= afsconf_Open(FS_configPath
);
273 ("hpr_Initialize: Could not open configuration directory: %s\n",
278 code
= afsconf_GetLocalCell(tdir
, cellstr
, sizeof(cellstr
));
280 ViceLog(0, ("hpr_Initialize: Could not get local cell. [%d]\n", code
));
285 code
= afsconf_GetCellInfo(tdir
, cellstr
, "afsprot", &info
);
287 ViceLog(0, ("hpr_Initialize: Could not locate cell %s in %s/%s\n",
288 cellstr
, tdir
->name
, AFSDIR_CELLSERVDB_FILE
));
295 ViceLog(0, ("hpr_Initialize: Could not initialize rx.\n"));
300 /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
301 * to force use of the KeyFile. secLevel == 0 implies -noauth was
303 code
= afsconf_ClientAuthSecure(tdir
, &sc
, &scIndex
);
305 ViceLog(0, ("hpr_Initialize: clientauthsecure returns %d %s "
306 "(so trying noauth)\n", code
, afs_error_message(code
)));
307 scIndex
= RX_SECIDX_NULL
;
308 sc
= rxnull_NewClientSecurityObject();
311 if (scIndex
== RX_SECIDX_NULL
)
312 ViceLog(0, ("hpr_Initialize: Could not get afs tokens, "
313 "running unauthenticated. [%d]\n", code
));
315 memset(serverconns
, 0, sizeof(serverconns
)); /* terminate list!!! */
316 for (i
= 0; i
< info
.numServers
; i
++) {
318 rx_NewConnection(info
.hostAddr
[i
].sin_addr
.s_addr
,
319 info
.hostAddr
[i
].sin_port
, PRSRV
,
323 code
= ubik_ClientInit(serverconns
, uclient
);
325 ViceLog(0, ("hpr_Initialize: ubik client init failed. [%d]\n", code
));
328 code2
= rxs_Release(sc
);
337 hpr_End(struct ubik_client
*uclient
)
342 code
= ubik_ClientDestroy(uclient
);
348 getThreadClient(struct ubik_client
**client
)
352 *client
= pthread_getspecific(viced_uclient_key
);
356 code
= hpr_Initialize(client
);
360 opr_Verify(pthread_setspecific(viced_uclient_key
, *client
) == 0);
366 hpr_GetHostCPS(afs_int32 host
, prlist
*CPS
)
370 struct ubik_client
*uclient
;
372 code
= getThreadClient(&uclient
);
377 code
= ubik_PR_GetHostCPS(uclient
, 0, host
, CPS
, &over
);
378 if (code
!= PRSUCCESS
)
381 /* do something about this, probably make a new call */
382 /* don't forget there's a hard limit in the interface */
384 "membership list for host id %d exceeds display limit\n",
391 hpr_NameToId(namelist
*names
, idlist
*ids
)
395 struct ubik_client
*uclient
;
397 code
= getThreadClient(&uclient
);
401 for (i
= 0; i
< names
->namelist_len
; i
++)
402 stolower(names
->namelist_val
[i
]);
403 code
= ubik_PR_NameToID(uclient
, 0, names
, ids
);
408 hpr_IdToName(idlist
*ids
, namelist
*names
)
411 struct ubik_client
*uclient
;
413 code
= getThreadClient(&uclient
);
417 code
= string_PR_IDToName(uclient
, 0, ids
, names
);
422 hpr_GetCPS(afs_int32 id
, prlist
*CPS
)
426 struct ubik_client
*uclient
;
428 code
= getThreadClient(&uclient
);
433 code
= ubik_PR_GetCPS(uclient
, 0, id
, CPS
, &over
);
434 if (code
!= PRSUCCESS
)
437 /* do something about this, probably make a new call */
438 /* don't forget there's a hard limit in the interface */
439 fprintf(stderr
, "membership list for id %d exceeds display limit\n",
445 static short consolePort
= 0;
448 h_Lock_r(struct host
*host
)
458 * returns 1 if already locked
459 * else returns locks and returns 0
463 h_NBLock_r(struct host
*host
)
465 struct Lock
*hostLock
= &host
->lock
;
470 if (!(hostLock
->excl_locked
) && !(hostLock
->readers_reading
))
471 hostLock
->excl_locked
= WRITE_LOCK
;
475 LOCK_UNLOCK(hostLock
);
484 /*------------------------------------------------------------------------
485 * PRIVATE h_AddrInSameNetwork
488 * Given a target IP address and a candidate IP address (both
489 * in host byte order), return a non-zero value (1) if the
490 * candidate address is in a different network from the target
494 * a_targetAddr : Target address.
495 * a_candAddr : Candidate address.
498 * 1 if the candidate address is in the same net as the target,
502 * The target and candidate addresses are both in host byte
503 * order, NOT network byte order, when passed in. We return
504 * our value as a character, since that's the type of field in
505 * the host structure, where this info will be stored.
509 *------------------------------------------------------------------------*/
512 h_AddrInSameNetwork(afs_uint32 a_targetAddr
, afs_uint32 a_candAddr
)
513 { /*h_AddrInSameNetwork */
515 afs_uint32 targetNet
;
519 * Pull out the network and subnetwork numbers from the target
520 * and candidate addresses. We can short-circuit this whole
521 * affair if the target and candidate addresses are not of the
524 if (IN_CLASSA(a_targetAddr
)) {
525 if (!(IN_CLASSA(a_candAddr
))) {
528 targetNet
= a_targetAddr
& IN_CLASSA_NET
;
529 candNet
= a_candAddr
& IN_CLASSA_NET
;
530 } else if (IN_CLASSB(a_targetAddr
)) {
531 if (!(IN_CLASSB(a_candAddr
))) {
534 targetNet
= a_targetAddr
& IN_CLASSB_NET
;
535 candNet
= a_candAddr
& IN_CLASSB_NET
;
536 } /*Class B target */
537 else if (IN_CLASSC(a_targetAddr
)) {
538 if (!(IN_CLASSC(a_candAddr
))) {
541 targetNet
= a_targetAddr
& IN_CLASSC_NET
;
542 candNet
= a_candAddr
& IN_CLASSC_NET
;
543 } /*Class C target */
545 targetNet
= a_targetAddr
;
546 candNet
= a_candAddr
;
547 } /*Class D address */
550 * Now, simply compare the extracted net values for the two addresses
551 * (which at this point are known to be of the same class)
553 if (targetNet
== candNet
)
558 } /*h_AddrInSameNetwork */
561 /* Assumptions: called with held host */
563 h_gethostcps_r(struct host
*host
, afs_int32 now
)
568 /* wait if somebody else is already doing the getCPS call */
569 while (host
->z
.hostFlags
& HCPS_INPROGRESS
) {
570 slept
= 1; /* I did sleep */
571 host
->z
.hostFlags
|= HCPS_WAITING
; /* I am sleeping now */
572 opr_cv_wait(&host
->cond
, &host_glock_mutex
);
576 host
->z
.hostFlags
|= HCPS_INPROGRESS
; /* mark as CPSCall in progress */
577 if (host
->z
.hcps
.prlist_val
)
578 free(host
->z
.hcps
.prlist_val
); /* this is for hostaclRefresh */
579 host
->z
.hcps
.prlist_val
= NULL
;
580 host
->z
.hcps
.prlist_len
= 0;
581 host
->z
.cpsCall
= slept
? time(NULL
) : (now
);
584 code
= hpr_GetHostCPS(ntohl(host
->z
.host
), &host
->z
.hcps
);
589 * Although ubik_Call (called by pr_GetHostCPS) traverses thru all protection servers
590 * and reevaluates things if no sync server or quorum is found we could still end up
591 * with one of these errors. In such case we would like to reevaluate the rpc call to
592 * find if there's cps for this guy. We treat other errors (except network failures
593 * ones - i.e. code < 0) as an indication that there is no CPS for this host. Ideally
594 * we could like to deal this problem the other way around (i.e. if code == NOCPS
595 * ignore else retry next time) but the problem is that there're other errors (i.e.
596 * EPERM) for which we don't want to retry and we don't know the whole code list!
598 if (code
< 0 || code
== UNOQUORUM
|| code
== UNOTSYNC
) {
600 * We would have preferred to use a while loop and try again since ops in protected
601 * acls for this host will fail now but they'll be reevaluated on any subsequent
602 * call. The attempt to wait for a quorum/sync site or network error won't work
603 * since this problems really should only occurs during a complete fileserver
604 * restart. Since the fileserver will start before the ptservers (and thus before
605 * quorums are complete) clients will be utilizing all the fileserver's lwps!!
607 host
->z
.hcpsfailed
= 1;
609 ("Warning: GetHostCPS failed (%d) for %p (%s:%d); will retry\n",
610 code
, host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
612 host
->z
.hcpsfailed
= 0;
614 ("gethost: GetHostCPS failed (%d) for %p (%s:%d); ignored\n",
615 code
, host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
617 if (host
->z
.hcps
.prlist_val
)
618 free(host
->z
.hcps
.prlist_val
);
619 host
->z
.hcps
.prlist_val
= NULL
;
620 host
->z
.hcps
.prlist_len
= 0; /* Make sure it's zero */
622 host
->z
.hcpsfailed
= 0;
624 host
->z
.hostFlags
&= ~HCPS_INPROGRESS
;
625 /* signal all who are waiting */
626 if (host
->z
.hostFlags
& HCPS_WAITING
) { /* somebody is waiting */
627 host
->z
.hostFlags
&= ~HCPS_WAITING
;
628 opr_cv_broadcast(&host
->cond
);
632 /* args in net byte order */
634 h_flushhostcps(afs_uint32 hostaddr
, afs_uint16 hport
)
639 h_Lookup_r(hostaddr
, hport
, &host
);
641 host
->z
.hcpsfailed
= 1;
650 * Allocate a host. It will be identified by the peer (ip,port) info in the
651 * rx connection provided. The host is returned held and locked
653 #define DEF_ROPCONS 2115
656 h_Alloc_r(struct rx_connection
*r_con
)
658 struct servent
*serverentry
;
660 afs_uint32 newHostAddr_HBO
; /*New host IP addr, in host byte order */
667 /* acquire the host lock withot dropping H_LOCK. we can do this here
668 * because we know we will not block; we just created this host and
669 * nobody else knows about it. */
670 ObtainWriteLock(&host
->lock
);
672 host
->z
.host
= rxr_HostOf(r_con
);
673 host
->z
.port
= rxr_PortOf(r_con
);
675 h_AddHostToAddrHashTable_r(host
->z
.host
, host
->z
.port
, host
);
677 if (consolePort
== 0) { /* find the portal number for console */
678 #if defined(AFS_OSF_ENV)
679 serverentry
= getservbyname("ropcons", "");
681 serverentry
= getservbyname("ropcons", 0);
684 consolePort
= serverentry
->s_port
;
686 consolePort
= htons(DEF_ROPCONS
); /* Use a default */
688 if (host
->z
.port
== consolePort
)
690 /* Make a callback channel even for the console, on the off chance that it
691 * makes a request that causes a break call back. It shouldn't. */
692 h_SetupCallbackConn_r(host
);
693 host
->z
.LastCall
= host
->z
.cpsCall
= host
->z
.ActiveCall
= time(NULL
);
694 host
->z
.hostFlags
= 0;
695 host
->z
.hcps
.prlist_val
= NULL
;
696 host
->z
.hcps
.prlist_len
= 0;
697 host
->z
.interface
= NULL
;
699 host
->z
.hcpsfailed
= 0; /* save cycles */
700 h_gethostcps(host
); /* do this under host hold/lock */
702 host
->z
.FirstClient
= NULL
;
703 h_InsertList_r(host
); /* update global host List */
705 * Compare the new host's IP address (in host byte order) with ours
706 * (the File Server's), remembering if they are in the same network.
708 newHostAddr_HBO
= (afs_uint32
) ntohl(host
->z
.host
);
709 host
->z
.InSameNetwork
=
710 h_AddrInSameNetwork(FS_HostAddr_HBO
, newHostAddr_HBO
);
717 /* Make a callback channel even for the console, on the off chance that it
718 * makes a request that causes a break call back. It shouldn't. */
720 h_SetupCallbackConn_r(struct host
* host
)
723 sc
= rxnull_NewClientSecurityObject();
724 host
->z
.callback_rxcon
=
725 rx_NewConnection(host
->z
.host
, host
->z
.port
, 1, sc
, 0);
726 rx_SetConnDeadTime(host
->z
.callback_rxcon
, 50);
727 rx_SetConnHardDeadTime(host
->z
.callback_rxcon
, AFS_HARDDEADTIME
);
731 * Lookup a host given an IP address and UDP port number.
732 * hostaddr and hport are in network order
733 * hostaddr and hport are in network order
734 * On return, refCount is incremented.
737 h_Lookup_r(afs_uint32 haddr
, afs_uint16 hport
, struct host
**hostp
)
740 struct host
*host
= NULL
;
741 struct h_AddrHashChain
*chain
;
742 int index
= h_HashIndex(haddr
);
743 extern int hostaclRefresh
;
746 for (chain
= hostAddrHashTable
[index
]; chain
; chain
= chain
->next
) {
747 host
= chain
->hostPtr
;
749 if (!(host
->z
.hostFlags
& HOSTDELETED
) && chain
->addr
== haddr
750 && chain
->port
== hport
) {
751 if ((host
->z
.hostFlags
& HWHO_INPROGRESS
) &&
752 h_threadquota(host
->lock
.num_waiting
)) {
758 if (host
->z
.hostFlags
& HOSTDELETED
) {
765 now
= time(NULL
); /* always evaluate "now" */
766 if (host
->z
.hcpsfailed
|| (host
->z
.cpsCall
+ hostaclRefresh
< now
)) {
768 * Every hostaclRefresh period (def 2 hrs) get the new
769 * membership list for the host. Note this could be the
770 * first time that the host is added to a group. Also
771 * here we also retry on previous legitimate hcps failures.
773 * If we get here refCount is elevated.
775 h_gethostcps_r(host
, now
);
785 /* Lookup a host given its UUID. */
787 h_LookupUuid_r(afsUUID
* uuidp
)
789 struct host
*host
= 0;
790 struct h_UuidHashChain
*chain
;
791 int index
= h_UuidHashIndex(uuidp
);
793 for (chain
= hostUuidHashTable
[index
]; chain
; chain
= chain
->next
) {
794 host
= chain
->hostPtr
;
796 if (!(host
->z
.hostFlags
& HOSTDELETED
) && host
->z
.interface
797 && afs_uuid_equal(&host
->z
.interface
->uuid
, uuidp
)) {
805 /* h_TossStuff_r: Toss anything in the host structure (the host or
806 * clients marked for deletion. Called from h_Release_r ONLY.
807 * To be called, there must be no holds, and either host->z.deleted
808 * or host->clientDeleted must be set.
811 h_TossStuff_r(struct host
*host
)
813 struct client
**cp
, *client
;
817 if ((host
->z
.hostFlags
& HOSTDELETED
)) {
821 /* make sure host doesn't go away over h_NBLock_r */
824 code
= h_NBLock_r(host
);
826 /* don't use h_Release_r, since that may call h_TossStuff_r again */
829 /* if somebody still has this host locked */
833 /* someone locked the host while HOSTDELETED was set; that is bad */
834 ViceLog(0, ("Warning: h_TossStuff_r failed; Host %" AFS_PTR_FMT
835 " (%s:%d flags 0x%x) was locked.\n",
836 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
),
837 (unsigned)host
->z
.hostFlags
));
844 /* if somebody still has this host held */
845 /* we must check this _after_ h_NBLock_r, since h_NBLock_r can drop and
846 * reacquire H_LOCK */
847 if (host
->z
.refCount
> 0) {
850 /* someone grabbed a ref while HOSTDELETED was set; that is bad */
851 ViceLog(0, ("Warning: h_TossStuff_r failed; Host %" AFS_PTR_FMT
852 " (%s:%d flags 0x%x) was held.\n",
853 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
),
854 (unsigned)host
->z
.hostFlags
));
859 /* ASSUMPTION: rxi_FreeConnection() does not yield */
860 for (cp
= &host
->z
.FirstClient
; (client
= *cp
);) {
861 if ((host
->z
.hostFlags
& HOSTDELETED
) || client
->z
.deleted
) {
863 ObtainWriteLockNoBlock(&client
->lock
, code
);
867 ("Warning: h_TossStuff_r failed: Host %p (%s:%d) "
868 "client %p was locked.\n",
869 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
870 ntohs(host
->z
.port
), client
));
874 if (client
->z
.refCount
) {
877 ("Warning: h_TossStuff_r failed: Host %p (%s:%d) "
878 "client %p refcount %d.\n",
879 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
880 ntohs(host
->z
.port
), client
, client
->z
.refCount
));
881 /* This is the same thing we do if the host is locked */
882 ReleaseWriteLock(&client
->lock
);
885 client
->z
.CPS
.prlist_len
= 0;
886 if ((client
->z
.ViceId
!= ANONYMOUSID
) && client
->z
.CPS
.prlist_val
)
887 free(client
->z
.CPS
.prlist_val
);
888 client
->z
.CPS
.prlist_val
= NULL
;
889 CurrentConnections
--;
890 *cp
= client
->z
.next
;
891 ReleaseWriteLock(&client
->lock
);
894 cp
= &client
->z
.next
;
897 /* We've just cleaned out all the deleted clients; clear the flag */
898 host
->z
.hostFlags
&= ~CLIENTDELETED
;
900 if (host
->z
.hostFlags
& HOSTDELETED
) {
901 struct rx_connection
*rxconn
;
902 struct AddrPort hostAddrPort
;
905 if (host
->z
.Console
& 1)
907 if ((rxconn
= host
->z
.callback_rxcon
)) {
908 host
->z
.callback_rxcon
= (struct rx_connection
*)0;
909 rx_DestroyConnection(rxconn
);
911 if (host
->z
.hcps
.prlist_val
)
912 free(host
->z
.hcps
.prlist_val
);
913 host
->z
.hcps
.prlist_val
= NULL
;
914 host
->z
.hcps
.prlist_len
= 0;
915 free(host
->z
.tmay_caps
.Capabilities_val
);
916 host
->z
.tmay_caps
.Capabilities_val
= NULL
;
917 host
->z
.tmay_caps
.Capabilities_len
= 0;
918 DeleteAllCallBacks_r(host
, 1);
919 host
->z
.hostFlags
&= ~RESETDONE
; /* just to be safe */
921 /* if alternate addresses do not exist */
922 if (!(host
->z
.interface
)) {
923 h_DeleteHostFromAddrHashTable_r(host
->z
.host
, host
->z
.port
, host
);
925 h_DeleteHostFromUuidHashTable_r(host
);
926 h_DeleteHostFromAddrHashTable_r(host
->z
.host
, host
->z
.port
, host
);
927 /* delete the hash entry for each valid alternate addresses */
928 for (i
= 0; i
< host
->z
.interface
->numberOfInterfaces
; i
++) {
929 hostAddrPort
= host
->z
.interface
->interface
[i
];
931 * if the interface addr/port is the primary, we already
932 * removed it. If the addr/port is not valid, its not
935 if (hostAddrPort
.valid
&&
936 (host
->z
.host
!= hostAddrPort
.addr
||
937 host
->z
.port
!= hostAddrPort
.port
))
938 h_DeleteHostFromAddrHashTable_r(hostAddrPort
.addr
, hostAddrPort
.port
, host
);
940 free(host
->z
.interface
);
941 host
->z
.interface
= NULL
;
942 } /* if alternate address exists */
944 h_DeleteList_r(host
); /* remove host from global host List */
951 /* h_Enumerate: Calls (*proc)(host, param) for at least each host in the
952 * system at the start of the enumeration (perhaps more). Hosts may be deleted
953 * (have delete flag set); ditto for clients. refCount is always incremented
954 * before (*proc) is called.
956 * The return value of the proc is a set of flags. The proc should set
957 * H_ENUMERATE_BAIL(foo) if the enumeration of hosts should be stopped early.
960 h_Enumerate(int (*proc
) (struct host
*, void *), void *param
)
962 struct host
*host
, **list
;
967 if (hostCount
== 0) {
971 list
= malloc(hostCount
* sizeof(struct host
*));
973 ViceLogThenPanic(0, ("Failed malloc in h_Enumerate (list)\n"));
975 for (totalCount
= count
= 0, host
= hostList
;
976 host
&& totalCount
< hostCount
;
977 host
= host
->z
.next
, totalCount
++) {
979 if (!(host
->z
.hostFlags
& HOSTDELETED
)) {
985 if (totalCount
!= hostCount
) {
986 ViceLog(0, ("h_Enumerate found %d of %d hosts\n", totalCount
, hostCount
));
987 } else if (host
!= NULL
) {
988 ViceLog(0, ("h_Enumerate found more than %d hosts\n", hostCount
));
989 ShutDownAndCore(PANIC
);
992 for (i
= 0; i
< count
; i
++) {
994 flags
= (*proc
) (list
[i
], param
);
996 h_Release_r(list
[i
]);
998 /* bail out of the enumeration early */
999 if (H_ENUMERATE_ISSET_BAIL(flags
)) {
1002 ViceLog(0, ("h_Enumerate got back invalid return value %d\n", flags
));
1003 ShutDownAndCore(PANIC
);
1007 /* we bailed out of enumerating hosts early; we still have holds on
1008 * some of the hosts in 'list', so release them */
1011 for ( ; i
< count
; i
++) {
1012 h_Release_r(list
[i
]);
1020 /* h_Enumerate_r (revised):
1021 * Calls (*proc)(host, param) for each host in hostList, starting
1022 * at enumstart. Called only under H_LOCK. Hosts may be deleted (have
1023 * delete flag set); ditto for clients. refCount is always incremented
1024 * before (*proc) is called.
1026 * @note Assumes that hostList is only prepended to, that a host is never
1027 * inserted into the middle. Otherwise this would not be guaranteed to
1030 * The return value of the proc is a set of flags. The proc should set
1031 * H_ENUMERATE_BAIL(foo) if the enumeration of hosts should be stopped early.
1034 h_Enumerate_r(int (*proc
) (struct host
*, void *),
1035 struct host
*enumstart
, void *param
)
1037 struct host
*host
, *next
;
1041 if (hostCount
== 0) {
1048 /* find the first non-deleted host, so we know where to actually start
1050 for (count
= 0; host
&& count
< hostCount
; count
++) {
1051 if (!(host
->z
.hostFlags
& HOSTDELETED
)) {
1055 host
= host
->z
.next
;
1058 /* we didn't find a non-deleted host... */
1060 if (host
&& count
>= hostCount
) {
1061 /* ...because we found a loop */
1062 ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", hostCount
));
1063 ShutDownAndCore(PANIC
);
1066 /* ...because the hostList is full of deleted hosts */
1070 h_Hold_r(enumstart
);
1072 /* remember hostCount, lest it change over the potential H_LOCK drop in
1074 origHostCount
= hostCount
;
1076 for (count
= 0, host
= enumstart
; host
&& count
< origHostCount
; host
= next
, count
++) {
1077 next
= host
->z
.next
;
1079 /* find the next non-deleted host */
1080 while (next
&& (next
->z
.hostFlags
& HOSTDELETED
)) {
1081 next
= next
->z
.next
;
1082 /* inc count for the skipped-over host */
1083 if (++count
> origHostCount
) {
1084 ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", origHostCount
));
1085 ShutDownAndCore(PANIC
);
1091 if (!(host
->z
.hostFlags
& HOSTDELETED
)) {
1093 flags
= (*proc
) (host
, param
);
1094 if (H_ENUMERATE_ISSET_BAIL(flags
)) {
1095 h_Release_r(host
); /* this might free up the host */
1101 ViceLog(0, ("h_Enumerate_r got back invalid return value %d\n", flags
));
1102 ShutDownAndCore(PANIC
);
1105 h_Release_r(host
); /* this might free up the host */
1107 if (host
!= NULL
&& count
>= origHostCount
) {
1108 ViceLog(0, ("h_Enumerate_r found more than %d hosts\n", origHostCount
));
1109 ShutDownAndCore(PANIC
);
1111 } /*h_Enumerate_r */
1114 /* inserts a new HashChain structure corresponding to this UUID */
1116 h_AddHostToUuidHashTable_r(struct afsUUID
*uuid
, struct host
*host
)
1119 struct h_UuidHashChain
*chain
;
1120 char uuid1
[128], uuid2
[128];
1123 /* hash into proper bucket */
1124 index
= h_UuidHashIndex(uuid
);
1126 /* don't add the same entry multiple times */
1127 for (chain
= hostUuidHashTable
[index
]; chain
; chain
= chain
->next
) {
1128 if (!chain
->hostPtr
)
1131 if (chain
->hostPtr
->z
.interface
&&
1132 afs_uuid_equal(&chain
->hostPtr
->z
.interface
->uuid
, uuid
)) {
1133 if (GetLogLevel() >= 125) {
1134 afsUUID_to_string(&chain
->hostPtr
->z
.interface
->uuid
, uuid1
,
1136 afsUUID_to_string(uuid
, uuid2
, 127);
1137 ViceLog(125, ("h_AddHostToUuidHashTable_r: host %" AFS_PTR_FMT
" (uuid %s) exists as %s:%d (uuid %s)\n",
1139 afs_inet_ntoa_r(chain
->hostPtr
->z
.host
, hoststr
),
1140 ntohs(chain
->hostPtr
->z
.port
), uuid2
));
1146 /* insert into beginning of list for this bucket */
1147 chain
= malloc(sizeof(struct h_UuidHashChain
));
1149 ViceLogThenPanic(0, ("Failed malloc in h_AddHostToUuidHashTable_r\n"));
1151 chain
->hostPtr
= host
;
1152 chain
->next
= hostUuidHashTable
[index
];
1153 hostUuidHashTable
[index
] = chain
;
1154 if (GetLogLevel() < 125)
1156 afsUUID_to_string(uuid
, uuid2
, 127);
1158 ("h_AddHostToUuidHashTable_r: host %p (%s:%d) added as uuid %s\n",
1159 host
, afs_inet_ntoa_r(chain
->hostPtr
->z
.host
, hoststr
),
1160 ntohs(chain
->hostPtr
->z
.port
), uuid2
));
1163 /* deletes a HashChain structure corresponding to this host */
1165 h_DeleteHostFromUuidHashTable_r(struct host
*host
)
1168 struct h_UuidHashChain
**uhp
, *uth
;
1172 if (!host
->z
.interface
)
1175 /* hash into proper bucket */
1176 index
= h_UuidHashIndex(&host
->z
.interface
->uuid
);
1178 if (GetLogLevel() >= 125)
1179 afsUUID_to_string(&host
->z
.interface
->uuid
, uuid1
, 127);
1180 for (uhp
= &hostUuidHashTable
[index
]; (uth
= *uhp
); uhp
= &uth
->next
) {
1181 opr_Assert(uth
->hostPtr
);
1182 if (uth
->hostPtr
== host
) {
1184 ("h_DeleteHostFromUuidHashTable_r: host %" AFS_PTR_FMT
" (uuid %s %s:%d)\n",
1185 host
, uuid1
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1186 ntohs(host
->z
.port
)));
1193 ("h_DeleteHostFromUuidHashTable_r: host %" AFS_PTR_FMT
" (uuid %s %s:%d) not found\n",
1194 host
, uuid1
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1195 ntohs(host
->z
.port
)));
1200 * This is called with host locked and held.
1202 * All addresses are in network byte order.
1205 invalidateInterfaceAddr_r(struct host
*host
, afs_uint32 addr
, afs_uint16 port
)
1209 struct Interface
*interface
;
1210 char hoststr
[16], hoststr2
[16];
1213 opr_Assert(host
->z
.interface
);
1215 ViceLog(125, ("invalidateInterfaceAddr : host %" AFS_PTR_FMT
" (%s:%d) addr %s:%d\n",
1216 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1217 ntohs(host
->z
.port
), afs_inet_ntoa_r(addr
, hoststr2
),
1221 * Make sure this address is on the list of known addresses
1224 interface
= host
->z
.interface
;
1225 number
= host
->z
.interface
->numberOfInterfaces
;
1226 for (i
= 0; i
< number
; i
++) {
1227 if (interface
->interface
[i
].addr
== addr
&&
1228 interface
->interface
[i
].port
== port
) {
1229 if (interface
->interface
[i
].valid
) {
1230 h_DeleteHostFromAddrHashTable_r(addr
, port
, host
);
1231 interface
->interface
[i
].valid
= 0;
1242 * This is called with host locked and held. This function differs
1243 * from removeInterfaceAddr_r in that it is called when the address
1244 * is being removed from the host regardless of whether or not there
1245 * is an interface list for the host. This function will delete the
1246 * host if there are no addresses left on it.
1248 * All addresses are in network byte order.
1251 removeAddress_r(struct host
*host
, afs_uint32 addr
, afs_uint16 port
)
1254 char hoststr
[16], hoststr2
[16];
1255 struct rx_connection
*rxconn
;
1257 if (!host
->z
.interface
|| host
->z
.interface
->numberOfInterfaces
== 1) {
1258 if (host
->z
.host
== addr
&& host
->z
.port
== port
) {
1260 ("Removing only address for host %" AFS_PTR_FMT
" (%s:%d), deleting host.\n",
1261 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
1262 host
->z
.hostFlags
|= HOSTDELETED
;
1264 * Do not remove the primary addr/port from the hash table.
1265 * It will be ignored due to the HOSTDELETED flag and will
1266 * be removed when h_TossStuff_r() cleans up the HOSTDELETED
1267 * host. Removing it here will only result in a search for
1268 * the host/addr/port in the hash chain which will fail.
1272 ("Removing address that does not belong to host %" AFS_PTR_FMT
" (%s:%d).\n",
1273 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
1276 if (host
->z
.host
== addr
&& host
->z
.port
== port
) {
1277 removeInterfaceAddr_r(host
, addr
, port
);
1279 for (i
=0; i
< host
->z
.interface
->numberOfInterfaces
; i
++) {
1280 if (host
->z
.interface
->interface
[i
].valid
) {
1282 ("Removed address for host %" AFS_PTR_FMT
" (%s:%d), new primary interface %s:%d.\n",
1283 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
),
1284 afs_inet_ntoa_r(host
->z
.interface
->interface
[i
].addr
, hoststr2
),
1285 ntohs(host
->z
.interface
->interface
[i
].port
)));
1286 host
->z
.host
= host
->z
.interface
->interface
[i
].addr
;
1287 host
->z
.port
= host
->z
.interface
->interface
[i
].port
;
1288 h_AddHostToAddrHashTable_r(host
->z
.host
, host
->z
.port
, host
);
1293 if (i
== host
->z
.interface
->numberOfInterfaces
) {
1295 ("Removed only address for host %" AFS_PTR_FMT
" (%s:%d), no valid alternate interfaces, deleting host.\n",
1296 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
1297 host
->z
.hostFlags
|= HOSTDELETED
;
1298 /* addr/port was removed from the hash table */
1302 rxconn
= host
->z
.callback_rxcon
;
1303 host
->z
.callback_rxcon
= NULL
;
1306 rx_DestroyConnection(rxconn
);
1310 h_SetupCallbackConn_r(host
);
1313 /* not the primary addr/port, just invalidate it */
1314 invalidateInterfaceAddr_r(host
, addr
, port
);
1322 createHostAddrHashChain_r(int index
, afs_uint32 addr
, afs_uint16 port
, struct host
*host
)
1324 struct h_AddrHashChain
*chain
;
1327 /* insert into beginning of list for this bucket */
1328 chain
= malloc(sizeof(struct h_AddrHashChain
));
1330 ViceLogThenPanic(0, ("Failed malloc in h_AddHostToAddrHashTable_r\n"));
1332 chain
->hostPtr
= host
;
1333 chain
->next
= hostAddrHashTable
[index
];
1336 hostAddrHashTable
[index
] = chain
;
1337 ViceLog(125, ("h_AddHostToAddrHashTable_r: host %" AFS_PTR_FMT
" added as %s:%d\n",
1338 host
, afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
)));
1342 * Resolve host address conflicts when hashing by address.
1344 * @param[in] addr an ip address of the interface
1345 * @param[in] port the port of the interface
1346 * @param[in] newHost the host being added with this address
1347 * @param[in] oldHost the host previously added with this address
1350 reconcileHosts_r(afs_uint32 addr
, afs_uint16 port
, struct host
*newHost
,
1351 struct host
*oldHost
)
1353 struct rx_connection
*cb
= NULL
;
1355 struct interfaceAddr interf
;
1357 afsUUID
*newHostUuid
= &nulluuid
;
1358 afsUUID
*oldHostUuid
= &nulluuid
;
1362 ("reconcileHosts_r: addr %s:%d newHost %" AFS_PTR_FMT
" oldHost %"
1363 AFS_PTR_FMT
"\n", afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
),
1366 opr_Assert(oldHost
!= newHost
);
1367 caps
.Capabilities_val
= NULL
;
1370 sc
= rxnull_NewClientSecurityObject();
1373 cb
= rx_NewConnection(addr
, port
, 1, sc
, 0);
1374 rx_SetConnDeadTime(cb
, 50);
1375 rx_SetConnHardDeadTime(cb
, AFS_HARDDEADTIME
);
1380 code
= RXAFSCB_TellMeAboutYourself(cb
, &interf
, &caps
);
1381 if (code
== RXGEN_OPCODE
) {
1382 code
= RXAFSCB_WhoAreYou(cb
, &interf
);
1386 if (code
== RXGEN_OPCODE
||
1387 (code
== 0 && afs_uuid_equal(&interf
.uuid
, &nulluuid
))) {
1389 ("reconcileHosts_r: WhoAreYou not supported for connection (%s:%d), error %d\n",
1390 afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
), code
));
1395 ("reconcileHosts_r: WhoAreYou failed for connection (%s:%d), error %d\n",
1396 afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
), code
));
1400 /* Since lock was dropped, the hosts may have been deleted during the rpcs. */
1401 if ((newHost
->z
.hostFlags
& HOSTDELETED
)
1402 && (oldHost
->z
.hostFlags
& HOSTDELETED
)) {
1404 ("reconcileHosts_r: new and old hosts were deleted during probe.\n"));
1408 /* A check can be done if at least one of the hosts has a uuid. It
1409 * is an error if the hosts have the same (not null) uuid. */
1410 if ((!(newHost
->z
.hostFlags
& HOSTDELETED
)) && newHost
->z
.interface
) {
1411 newHostUuid
= &(newHost
->z
.interface
->uuid
);
1413 if ((!(oldHost
->z
.hostFlags
& HOSTDELETED
)) && oldHost
->z
.interface
) {
1414 oldHostUuid
= &(oldHost
->z
.interface
->uuid
);
1416 if (afs_uuid_equal(newHostUuid
, &nulluuid
) &&
1417 afs_uuid_equal(oldHostUuid
, &nulluuid
)) {
1419 ("reconcileHosts_r: Cannot reconcile hosts for connection (%s:%d), no uuids\n",
1420 afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
)));
1423 if (afs_uuid_equal(newHostUuid
, oldHostUuid
)) {
1425 ("reconcileHosts_r: Cannot reconcile hosts for connection (%s:%d), same uuids\n",
1426 afs_inet_ntoa_r(addr
, hoststr
), ntohs(port
)));
1430 /* Determine which host should be hashed */
1431 if ((!(newHost
->z
.hostFlags
& HOSTDELETED
))
1432 && afs_uuid_equal(newHostUuid
, &(interf
.uuid
))) {
1433 /* Install the new host into the hash before removing the stale
1434 * addresses. Walk the hash chain again since the hash table may have
1435 * been changed when the host lock was dropped to get the uuid. */
1436 struct h_AddrHashChain
*chain
;
1437 int index
= h_HashIndex(addr
);
1438 for (chain
= hostAddrHashTable
[index
]; chain
; chain
= chain
->next
) {
1439 if (chain
->addr
== addr
&& chain
->port
== port
) {
1440 chain
->hostPtr
= newHost
;
1441 removeAddress_r(oldHost
, addr
, port
);
1445 createHostAddrHashChain_r(index
, addr
, port
, newHost
);
1446 removeAddress_r(oldHost
, addr
, port
);
1449 if ((!(oldHost
->z
.hostFlags
& HOSTDELETED
))
1450 && afs_uuid_equal(oldHostUuid
, &(interf
.uuid
))) {
1451 removeAddress_r(newHost
, addr
, port
);
1456 if (!(newHost
->z
.hostFlags
& HOSTDELETED
)) {
1457 removeAddress_r(newHost
, addr
, port
);
1459 if (!(oldHost
->z
.hostFlags
& HOSTDELETED
)) {
1460 removeAddress_r(oldHost
, addr
, port
);
1464 h_Release_r(newHost
);
1465 h_Release_r(oldHost
);
1466 rx_DestroyConnection(cb
);
1470 /* inserts a new HashChain structure corresponding to this address */
1472 h_AddHostToAddrHashTable_r(afs_uint32 addr
, afs_uint16 port
, struct host
*host
)
1475 struct h_AddrHashChain
*chain
;
1478 /* hash into proper bucket */
1479 index
= h_HashIndex(addr
);
1481 /* don't add the same address:port pair entry multiple times */
1482 for (chain
= hostAddrHashTable
[index
]; chain
; chain
= chain
->next
) {
1483 if (chain
->addr
== addr
&& chain
->port
== port
) {
1484 if (chain
->hostPtr
== host
) {
1486 ("h_AddHostToAddrHashTable_r: host %" AFS_PTR_FMT
" (%s:%d) already hashed\n",
1487 host
, afs_inet_ntoa_r(chain
->addr
, hoststr
),
1488 ntohs(chain
->port
)));
1491 if (!(chain
->hostPtr
->z
.hostFlags
& HOSTDELETED
)) {
1492 /* attempt to resolve host address collision */
1493 reconcileHosts_r(addr
, port
, host
, chain
->hostPtr
);
1498 createHostAddrHashChain_r(index
, addr
, port
, host
);
1502 * This is called with host locked and held.
1503 * It is called to either validate or add an additional interface
1504 * address/port on the specified host.
1506 * All addresses are in network byte order.
1509 addInterfaceAddr_r(struct host
*host
, afs_uint32 addr
, afs_uint16 port
)
1513 struct Interface
*interface
;
1514 char hoststr
[16], hoststr2
[16];
1517 opr_Assert(host
->z
.interface
);
1520 * Make sure this address is on the list of known addresses
1523 number
= host
->z
.interface
->numberOfInterfaces
;
1524 for (i
= 0; i
< number
; i
++) {
1525 if (host
->z
.interface
->interface
[i
].addr
== addr
&&
1526 host
->z
.interface
->interface
[i
].port
== port
) {
1528 ("addInterfaceAddr : found host %" AFS_PTR_FMT
" (%s:%d) adding %s:%d%s\n",
1529 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1530 ntohs(host
->z
.port
), afs_inet_ntoa_r(addr
, hoststr2
),
1531 ntohs(port
), host
->z
.interface
->interface
[i
].valid
? "" :
1534 if (host
->z
.interface
->interface
[i
].valid
== 0) {
1535 host
->z
.interface
->interface
[i
].valid
= 1;
1536 h_AddHostToAddrHashTable_r(addr
, port
, host
);
1542 ViceLog(125, ("addInterfaceAddr : host %" AFS_PTR_FMT
" (%s:%d) adding %s:%d\n",
1543 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1544 ntohs(host
->z
.port
), afs_inet_ntoa_r(addr
, hoststr2
),
1547 interface
= malloc(sizeof(struct Interface
)
1548 + (sizeof(struct AddrPort
) * number
));
1550 ViceLogThenPanic(0, ("Failed malloc in addInterfaceAddr_r\n"));
1552 interface
->numberOfInterfaces
= number
+ 1;
1553 interface
->uuid
= host
->z
.interface
->uuid
;
1554 for (i
= 0; i
< number
; i
++)
1555 interface
->interface
[i
] = host
->z
.interface
->interface
[i
];
1557 /* Add the new valid interface */
1558 interface
->interface
[number
].addr
= addr
;
1559 interface
->interface
[number
].port
= port
;
1560 interface
->interface
[number
].valid
= 1;
1561 h_AddHostToAddrHashTable_r(addr
, port
, host
);
1562 free(host
->z
.interface
);
1563 host
->z
.interface
= interface
;
1570 * This is called with host locked and held.
1572 * All addresses are in network byte order.
1575 removeInterfaceAddr_r(struct host
*host
, afs_uint32 addr
, afs_uint16 port
)
1579 struct Interface
*interface
;
1580 char hoststr
[16], hoststr2
[16];
1583 opr_Assert(host
->z
.interface
);
1585 ViceLog(125, ("removeInterfaceAddr : host %" AFS_PTR_FMT
" (%s:%d) addr %s:%d\n",
1586 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1587 ntohs(host
->z
.port
), afs_inet_ntoa_r(addr
, hoststr2
),
1591 * Make sure this address is on the list of known addresses
1594 interface
= host
->z
.interface
;
1595 number
= host
->z
.interface
->numberOfInterfaces
;
1596 for (i
= 0; i
< number
; i
++) {
1597 if (interface
->interface
[i
].addr
== addr
&&
1598 interface
->interface
[i
].port
== port
) {
1599 if (interface
->interface
[i
].valid
)
1600 h_DeleteHostFromAddrHashTable_r(addr
, port
, host
);
1602 for (; i
< number
; i
++) {
1603 interface
->interface
[i
] = interface
->interface
[i
+1];
1605 interface
->numberOfInterfaces
= number
;
1614 * The following few functions deal with caching TellMeAboutYourself calls
1615 * that we issued to clients. Why do we do this? Well:
1617 * Q: First, why do we need to issue a TMAY against a client on an incoming new
1620 * A: We must verify that the incoming Rx connection is the same host that
1621 * we have a 'host' structure for. On new calls for existing connections, we
1622 * can remember which host corresponds to that connection, but for new
1623 * connections, we have no way to find what host it is for, except by looking
1624 * up the host by IP address. Since hosts can change IP addresses, we need to
1625 * contact the IP address to see if it's the host we think it is.
1627 * Q: Okay, then why cache the results?
1629 * A: The TMAY calls to a single host are serialized, because they are issued
1630 * with the host's host->lock held. If we get 4 Rx calls each on new
1631 * connections to the same host at the same time, the 1st call will lock the
1632 * host, and issue a TMAY. Once that's done, the second call will issue a
1633 * TMAY, then the 3rd and then the 4th. However, the 3rd and 4th calls have
1634 * been waiting to issue a TMAY since before the 2nd call even _started_ to
1635 * issue a TMAY. So, we can just effectively give the results of the 2nd
1636 * call's TMAY to the 3rd and 4th, too. Since it is nondeterministic which of
1637 * those calls gets to issue a TMAY "first", we can just assume they all got
1640 * Note that in the above example, we cannot reuse the results of the 1st TMAY
1641 * for the 2nd, 3rd, and 4th calls (we only reuse the results of the 2nd).
1642 * This is because by the time the 2nd call starts waiting for the host lock,
1643 * it doesn't know how long the 1st TMAY has been running, so the 2nd call
1644 * might indeed get a different TMAY result (though this probably would be
1647 * Anyway, so, if we don't cache the results, we are issuing TMAYs that are
1648 * pure overhead. In an environment with clients that create a lot of
1649 * connections to a fileserver (keep in mind each new PAG on OpenAFS clients
1650 * creates a new connection), this can mean a significant amount of overhead.
1651 * So, we use this "TMAY cache" to avoid this overhead for the common case.
1655 * Should we skip calling TellMeAboutYourself on this host, and instead rely
1656 * on cached TMAY results?
1658 * @param[in] host The host we are dealing with
1659 * @param[in] prewait_tmays What the value of host->z.n_tmays was _before_ we
1661 * @param[in] prewait_host What the primary IP address for 'host' was before
1663 * @param[in] prewait_port What the primary port was for 'host' before we
1666 * @return Whether we should skip calling TMAY, and instead rely on cached
1670 ShouldSkipTMAY(struct host
*host
, int prewait_tmays
, afs_uint32 prewait_host
,
1671 afs_uint16 prewait_port
)
1674 if (host
->z
.n_tmays
> prewait_tmays
+ 1) {
1675 /* while we were waiting for the host lock, the in-progress TMAY
1676 * call finished, someone else started a new TMAY call, and that
1677 * finished. so, calling TMAY again won't give us any information
1678 * or additional guarantees. */
1681 if (host
->z
.host
!= prewait_host
|| host
->z
.port
!= prewait_port
) {
1682 /* ...but don't skip it if the host has changed */
1689 * If appropriate, simulate a TellMeAboutYourself call on 'host' by extracting
1690 * cached interfaceAddr and Capabilities information from 'host' itself.
1692 * @param[in] host The host we're dealing with
1693 * @param[inout] askiptmay On entering this function, this should contain the
1694 * result of ShouldSkipTMAY. On return, it is 1 if we
1695 * actually did use cached TMAY results, or 0 if we
1697 * @param[out] interf The interfaceAddr result of the simulated TMAY call
1698 * @param[out] caps The Capabilities result of the simulated TMAY call
1701 * @retval 0 We used the cached TMAY results; do NOT make a real TMAY request
1702 * @retval otherwise We did not use cached TMAY results; issue a real TMAY request
1705 SimulateTMAY(struct host
*host
, int *askiptmay
, struct interfaceAddr
*interf
,
1711 /* we're not supposed to skip the actual TMAY call */
1715 *interf
= host
->z
.tmay_interf
;
1717 free(caps
->Capabilities_val
);
1718 caps
->Capabilities_val
= NULL
;
1719 caps
->Capabilities_len
= 0;
1721 if (!host
->z
.tmay_caps
.Capabilities_val
) {
1725 capsize
= sizeof(caps
->Capabilities_val
[0]) * host
->z
.tmay_caps
.Capabilities_len
;
1727 caps
->Capabilities_val
= malloc(capsize
);
1728 if (!caps
->Capabilities_val
) {
1729 /* we should/did _not_ skip the real TMAY call, since we couldn't
1730 * alloc memory to use the cached results */
1734 caps
->Capabilities_len
= host
->z
.tmay_caps
.Capabilities_len
;
1735 memcpy(caps
->Capabilities_val
, host
->z
.tmay_caps
.Capabilities_val
, capsize
);
1741 * If appropriate, store the given results from a real TellmeAboutYourself
1742 * call, and cache them in the given host structure.
1744 * @param[in] host The host we're dealing with
1745 * @param[in] skiptmay 1 if we skipped making a real TMAY call, 0 otherwise
1746 * @param[in] didtmay 1 if we issued a successful real TMAY call, 0 otherwise
1747 * @param[in] interf The interfaceAddr result from the real TMAY call
1748 * @param[in] caps The Capabilities result from the real TMAY call
1751 CacheTMAY(struct host
*host
, int skiptmay
, int didtmay
,
1752 struct interfaceAddr
*interf
, Capabilities
*caps
)
1757 /* we simulated the TMAY call, so the state of the world hasn't
1758 * changed; don't touch anything */
1762 /* we did not perform a successful TMAY, so we don't have valid
1763 * results to cache. blow away the existing cache so we don't use
1767 if (host
->z
.n_tmays
== INT_MAX
) {
1768 /* make sure int rollover doesn't screw up our ordering */
1771 if (host
->lock
.num_waiting
== 0) {
1772 /* nobody is waiting for this host, so no reason to cache anything */
1776 /* okay, if we got here, everything looks good; let's cache the given
1777 * 'interf' and 'caps' */
1779 host
->z
.tmay_interf
= *interf
;
1781 if (!caps
->Capabilities_val
) {
1782 free(host
->z
.tmay_caps
.Capabilities_val
);
1783 host
->z
.tmay_caps
.Capabilities_val
= NULL
;
1784 host
->z
.tmay_caps
.Capabilities_len
= 0;
1787 if (caps
->Capabilities_len
!= host
->z
.tmay_caps
.Capabilities_len
) {
1788 free(host
->z
.tmay_caps
.Capabilities_val
);
1789 host
->z
.tmay_caps
.Capabilities_val
= NULL
;
1790 host
->z
.tmay_caps
.Capabilities_len
= 0;
1793 capsize
= sizeof(caps
->Capabilities_val
[0]) * caps
->Capabilities_len
;
1795 if (!host
->z
.tmay_caps
.Capabilities_val
) {
1796 host
->z
.tmay_caps
.Capabilities_val
= malloc(capsize
);
1797 if (!host
->z
.tmay_caps
.Capabilities_val
) {
1802 host
->z
.tmay_caps
.Capabilities_len
= caps
->Capabilities_len
;
1803 memcpy(host
->z
.tmay_caps
.Capabilities_val
, caps
->Capabilities_val
, capsize
);
1809 /* blow away the cached TMAY data; pretend we never saw anything */
1810 free(host
->z
.tmay_caps
.Capabilities_val
);
1811 host
->z
.tmay_caps
.Capabilities_val
= NULL
;
1812 host
->z
.tmay_caps
.Capabilities_len
= 0;
1813 memset(&host
->z
.tmay_interf
, 0, sizeof(host
->z
.tmay_interf
));
1815 host
->z
.n_tmays
= 0;
1819 h_threadquota(int waiting
)
1821 if (waiting
> h_quota_limit
) {
1827 /* If found, host is returned with refCount incremented */
1829 h_GetHost_r(struct rx_connection
*tcon
)
1832 struct host
*oldHost
;
1834 struct interfaceAddr interf
;
1835 int interfValid
= 0;
1836 struct Identity
*identP
= NULL
;
1839 char hoststr
[16], hoststr2
[16];
1841 struct rx_connection
*cb_conn
= NULL
;
1842 struct rx_connection
*cb_in
= NULL
;
1844 caps
.Capabilities_val
= NULL
;
1846 haddr
= rxr_HostOf(tcon
);
1847 hport
= rxr_PortOf(tcon
);
1850 rx_DestroyConnection(cb_in
);
1853 if (caps
.Capabilities_val
)
1854 free(caps
.Capabilities_val
);
1855 caps
.Capabilities_val
= NULL
;
1856 caps
.Capabilities_len
= 0;
1859 if (h_Lookup_r(haddr
, hport
, &host
))
1861 identP
= (struct Identity
*)rx_GetSpecific(tcon
, rxcon_ident_key
);
1862 if (host
&& !identP
&& !(host
->z
.Console
& 1)) {
1863 /* This is a new connection, and we already have a host
1864 * structure for this address. Verify that the identity
1865 * of the caller matches the identity in the host structure.
1868 int didtmay
= 0; /* did we make a successful TMAY call against host->z.host? */
1869 unsigned int prewait_tmays
;
1870 afs_uint32 prewait_host
;
1871 afs_uint16 prewait_port
;
1874 if ((host
->z
.hostFlags
& HWHO_INPROGRESS
) &&
1875 h_threadquota(host
->lock
.num_waiting
)) {
1881 prewait_tmays
= host
->z
.n_tmays
;
1882 prewait_host
= host
->z
.host
;
1883 prewait_port
= host
->z
.port
;
1886 if (!(host
->z
.hostFlags
& ALTADDR
) ||
1887 (host
->z
.hostFlags
& HOSTDELETED
)) {
1888 /* Another thread is doing initialization
1889 * or this host was deleted while we
1890 * waited for the lock. */
1893 ("Host %" AFS_PTR_FMT
" (%s:%d) starting h_Lookup again\n",
1894 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1895 ntohs(host
->z
.port
)));
1899 host
->z
.hostFlags
|= HWHO_INPROGRESS
;
1900 host
->z
.hostFlags
&= ~ALTADDR
;
1902 /* We received a new connection from an IP address/port
1903 * that is associated with 'host' but the address/port of
1904 * the callback connection does not have to match it.
1905 * If there is a match, we can use the existing callback
1906 * connection to verify the UUID. If they do not match
1907 * we need to use a new callback connection to verify the
1908 * UUID of the incoming caller and perhaps use the old
1909 * callback connection to verify that the old address/port
1913 cb_conn
= host
->z
.callback_rxcon
;
1914 rx_GetConnection(cb_conn
);
1916 skiptmay
= ShouldSkipTMAY(host
, prewait_tmays
, prewait_host
, prewait_port
);
1919 if (haddr
== host
->z
.host
&& hport
== host
->z
.port
) {
1920 /* The existing callback connection matches the
1921 * incoming connection so just use it.
1924 if (SimulateTMAY(host
, &skiptmay
, &interf
, &caps
) == 0) {
1925 /* noop; we don't need to call TellMeAboutYourself; we can
1926 * trust the results from the last TMAY call */
1931 RXAFSCB_TellMeAboutYourself(cb_conn
, &interf
, &caps
);
1932 if (code
== RXGEN_OPCODE
)
1933 code
= RXAFSCB_WhoAreYou(cb_conn
, &interf
);
1939 /* We do not have a match. Create a new connection
1940 * for the new addr/port and use multi_Rx to probe
1941 * both of them simultaneously.
1944 sc
= rxnull_NewClientSecurityObject();
1945 cb_in
= rx_NewConnection(haddr
, hport
, 1, sc
, 0);
1946 rx_SetConnDeadTime(cb_in
, 50);
1947 rx_SetConnHardDeadTime(cb_in
, AFS_HARDDEADTIME
);
1950 RXAFSCB_TellMeAboutYourself(cb_in
, &interf
, &caps
);
1951 if (code
== RXGEN_OPCODE
)
1952 code
= RXAFSCB_WhoAreYou(cb_in
, &interf
);
1954 rx_PutConnection(cb_conn
);
1958 CacheTMAY(host
, skiptmay
, didtmay
, &interf
, &caps
);
1960 if ((code
== RXGEN_OPCODE
) ||
1961 ((code
== 0) && (afs_uuid_equal(&interf
.uuid
, &nulluuid
)))) {
1962 identP
= malloc(sizeof(struct Identity
));
1964 ViceLogThenPanic(0, ("Failed malloc in h_GetHost_r\n"));
1967 rx_SetSpecific(tcon
, rxcon_ident_key
, identP
);
1968 if (cb_in
== NULL
) {
1969 /* The host on this connection was unable to respond to
1970 * the WhoAreYou. We will treat this as a new connection
1971 * from the existing host. The worst that can happen is
1972 * that we maintain some extra callback state information */
1973 if (host
->z
.interface
) {
1975 ("Host %" AFS_PTR_FMT
" (%s:%d) used to support WhoAreYou, deleting.\n",
1977 afs_inet_ntoa_r(host
->z
.host
, hoststr
),
1978 ntohs(host
->z
.port
)));
1979 host
->z
.hostFlags
|= HOSTDELETED
;
1980 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
1987 /* The incoming connection does not support WhoAreYou but
1988 * the original one might have. Use removeAddress_r() to
1989 * remove this addr/port from the host that was found.
1990 * If there are no more addresses left for the host it
1991 * will be deleted. Then we retry.
1993 removeAddress_r(host
, haddr
, hport
);
1994 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
1995 host
->z
.hostFlags
|= ALTADDR
;
2001 } else if (code
== 0) {
2003 identP
= malloc(sizeof(struct Identity
));
2005 ViceLogThenPanic(0, ("Failed malloc in h_GetHost_r\n"));
2008 identP
->uuid
= interf
.uuid
;
2009 rx_SetSpecific(tcon
, rxcon_ident_key
, identP
);
2010 /* Check whether the UUID on this connection matches
2011 * the UUID in the host structure. If they don't match
2012 * then this is not the same host as before. */
2013 if (!host
->z
.interface
2014 || !afs_uuid_equal(&interf
.uuid
, &host
->z
.interface
->uuid
)) {
2017 ("Uuid doesn't match connection (%s:%d).\n",
2018 afs_inet_ntoa_r(haddr
, hoststr
), ntohs(hport
)));
2019 removeAddress_r(host
, haddr
, hport
);
2022 ("Uuid doesn't match host %" AFS_PTR_FMT
" (%s:%d).\n",
2023 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
2025 removeAddress_r(host
, host
->z
.host
, host
->z
.port
);
2027 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
2028 host
->z
.hostFlags
|= ALTADDR
;
2034 /* the UUID matched the client at the incoming addr/port
2035 * but this is not the address of the active callback
2036 * connection. Try that connection and see if the client
2037 * is still there and if the reported UUID is the same.
2040 afsUUID uuid
= host
->z
.interface
->uuid
;
2041 cb_conn
= host
->z
.callback_rxcon
;
2042 rx_GetConnection(cb_conn
);
2043 rx_SetConnDeadTime(cb_conn
, 2);
2044 rx_SetConnHardDeadTime(cb_conn
, AFS_HARDDEADTIME
);
2046 code2
= RXAFSCB_ProbeUuid(cb_conn
, &uuid
);
2048 rx_SetConnDeadTime(cb_conn
, 50);
2049 rx_SetConnHardDeadTime(cb_conn
, AFS_HARDDEADTIME
);
2050 rx_PutConnection(cb_conn
);
2053 /* The primary address is either not responding or
2054 * is not the client we are looking for. Need to
2055 * remove the primary address and add swap in the new
2056 * callback connection, and destroy the old one.
2058 struct rx_connection
*rxconn
;
2059 ViceLog(0,("CB: ProbeUuid for host %" AFS_PTR_FMT
" (%s:%d) failed %d\n",
2061 afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2062 ntohs(host
->z
.port
),code2
));
2065 * make sure we add and then remove. otherwise, we
2066 * might end up with no valid interfaces after the
2067 * remove and the host will have been marked deleted.
2069 addInterfaceAddr_r(host
, haddr
, hport
);
2070 removeInterfaceAddr_r(host
, host
->z
.host
, host
->z
.port
);
2071 host
->z
.host
= haddr
;
2072 host
->z
.port
= hport
;
2073 rxconn
= host
->z
.callback_rxcon
;
2074 host
->z
.callback_rxcon
= cb_in
;
2079 * If rx_DestroyConnection calls h_FreeConnection we
2080 * will deadlock on the host_glock_mutex. Work around
2081 * the problem by unhooking the client from the
2082 * connection before destroying the connection.
2084 rx_SetSpecific(rxconn
, rxcon_client_key
, (void *)0);
2085 rx_DestroyConnection(rxconn
);
2091 /* A callback to the incoming connection address is failing.
2092 * Assume that the addr/port is no longer associated with the host
2093 * returned by h_Lookup_r.
2096 ("CB: WhoAreYou failed for connection (%s:%d) , error %d\n",
2097 afs_inet_ntoa_r(haddr
, hoststr
), ntohs(hport
), code
));
2098 removeAddress_r(host
, haddr
, hport
);
2099 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
2100 host
->z
.hostFlags
|= ALTADDR
;
2104 rx_DestroyConnection(cb_in
);
2109 ("CB: WhoAreYou failed for host %" AFS_PTR_FMT
" (%s:%d), error %d\n",
2110 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2111 ntohs(host
->z
.port
), code
));
2112 host
->z
.hostFlags
|= VENUSDOWN
;
2115 if (caps
.Capabilities_val
2116 && (caps
.Capabilities_val
[0] & CLIENT_CAPABILITY_ERRORTRANS
))
2117 host
->z
.hostFlags
|= HERRORTRANS
;
2119 host
->z
.hostFlags
&= ~(HERRORTRANS
);
2120 host
->z
.hostFlags
|= ALTADDR
;
2121 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
2124 if (!(host
->z
.hostFlags
& ALTADDR
)) {
2125 /* another thread is doing the initialisation */
2127 ("Host %" AFS_PTR_FMT
" (%s:%d) waiting for host-init to complete\n",
2128 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2129 ntohs(host
->z
.port
)));
2133 ("Host %" AFS_PTR_FMT
" (%s:%d) starting h_Lookup again\n",
2134 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2135 ntohs(host
->z
.port
)));
2139 /* We need to check whether the identity in the host structure
2140 * matches the identity on the connection. If they don't match
2141 * then treat this a new host. */
2142 if (!(host
->z
.Console
& 1)
2143 && ((!identP
->valid
&& host
->z
.interface
)
2144 || (identP
->valid
&& !host
->z
.interface
)
2146 && !afs_uuid_equal(&identP
->uuid
,
2147 &host
->z
.interface
->uuid
)))) {
2148 char uuid1
[128], uuid2
[128];
2150 afsUUID_to_string(&identP
->uuid
, uuid1
, 127);
2151 if (host
->z
.interface
)
2152 afsUUID_to_string(&host
->z
.interface
->uuid
, uuid2
, 127);
2154 ("CB: new identity for host %p (%s:%d), "
2155 "deleting(%x %p %s %s)\n",
2156 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
),
2157 identP
->valid
, host
->z
.interface
,
2158 identP
->valid
? uuid1
: "no_uuid",
2159 host
->z
.interface
? uuid2
: "no_uuid"));
2161 /* The host in the cache is not the host for this connection */
2163 host
->z
.hostFlags
|= HOSTDELETED
;
2169 host
= h_Alloc_r(tcon
); /* returned held and locked */
2172 h_gethostcps_r(host
, time(NULL
));
2173 if (!(host
->z
.Console
& 1)) {
2175 cb_conn
= host
->z
.callback_rxcon
;
2176 rx_GetConnection(cb_conn
);
2177 host
->z
.hostFlags
|= HWHO_INPROGRESS
;
2180 RXAFSCB_TellMeAboutYourself(cb_conn
, &interf
, &caps
);
2181 if (code
== RXGEN_OPCODE
)
2182 code
= RXAFSCB_WhoAreYou(cb_conn
, &interf
);
2183 rx_PutConnection(cb_conn
);
2186 if ((code
== RXGEN_OPCODE
) ||
2187 ((code
== 0) && (afs_uuid_equal(&interf
.uuid
, &nulluuid
)))) {
2189 identP
= malloc(sizeof(struct Identity
));
2194 ViceLogThenPanic(0, ("Failed malloc in h_GetHost_r\n"));
2198 rx_SetSpecific(tcon
, rxcon_ident_key
, identP
);
2200 ("Host %" AFS_PTR_FMT
" (%s:%d) does not support WhoAreYou.\n",
2201 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2202 ntohs(host
->z
.port
)));
2204 } else if (code
== 0) {
2206 identP
= malloc(sizeof(struct Identity
));
2211 ViceLogThenPanic(0, ("Failed malloc in h_GetHost_r\n"));
2215 identP
->uuid
= interf
.uuid
;
2217 rx_SetSpecific(tcon
, rxcon_ident_key
, identP
);
2219 ("WhoAreYou success on host %" AFS_PTR_FMT
" (%s:%d)\n",
2220 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2221 ntohs(host
->z
.port
)));
2223 if (code
== 0 && !identP
->valid
) {
2224 cb_conn
= host
->z
.callback_rxcon
;
2225 rx_GetConnection(cb_conn
);
2227 code
= RXAFSCB_InitCallBackState(cb_conn
);
2228 rx_PutConnection(cb_conn
);
2231 } else if (code
== 0) {
2232 oldHost
= h_LookupUuid_r(&identP
->uuid
);
2237 if (oldHost
->z
.hostFlags
& HOSTDELETED
) {
2238 h_Unlock_r(oldHost
);
2239 h_Release_r(oldHost
);
2247 /* This is a new address for an existing host. Update
2248 * the list of interfaces for the existing host and
2249 * delete the host structure we just allocated. */
2251 /* mark the duplicate host as deleted before we do
2252 * anything. The probing code below may try to change
2253 * "oldHost" to the same IP address as "host" currently
2254 * has, and we do not want a pseudo-"collision" to be
2256 host
->z
.hostFlags
|= HOSTDELETED
;
2258 oldHost
->z
.hostFlags
|= HWHO_INPROGRESS
;
2260 if (oldHost
->z
.interface
) {
2262 afsUUID uuid
= oldHost
->z
.interface
->uuid
;
2263 cb_conn
= oldHost
->z
.callback_rxcon
;
2264 rx_GetConnection(cb_conn
);
2265 rx_SetConnDeadTime(cb_conn
, 2);
2266 rx_SetConnHardDeadTime(cb_conn
, AFS_HARDDEADTIME
);
2268 code2
= RXAFSCB_ProbeUuid(cb_conn
, &uuid
);
2270 rx_SetConnDeadTime(cb_conn
, 50);
2271 rx_SetConnHardDeadTime(cb_conn
, AFS_HARDDEADTIME
);
2272 rx_PutConnection(cb_conn
);
2275 /* The primary address is either not responding or
2276 * is not the client we are looking for.
2277 * MultiProbeAlternateAddress_r() will remove the
2278 * alternate interfaces that do not have the same
2280 ViceLog(0,("CB: ProbeUuid for host %" AFS_PTR_FMT
" (%s:%d) failed %d\n",
2282 afs_inet_ntoa_r(oldHost
->z
.host
, hoststr
),
2283 ntohs(oldHost
->z
.port
),code2
));
2285 if (MultiProbeAlternateAddress_r(oldHost
)) {
2286 /* If MultiProbeAlternateAddress_r succeeded,
2287 * it updated oldHost->host and oldHost->port
2288 * to an address that responded successfully to
2289 * a ProbeUuid, so it is as if the ProbeUuid
2290 * call above returned success. So, only set
2291 * 'probefail' if MultiProbeAlternateAddress_r
2300 if (oldHost
->z
.host
!= haddr
|| oldHost
->z
.port
!= hport
) {
2301 struct rx_connection
*rxconn
;
2304 ("CB: Host %" AFS_PTR_FMT
" (%s:%d) has new addr %s:%d\n",
2306 afs_inet_ntoa_r(oldHost
->z
.host
, hoststr2
),
2307 ntohs(oldHost
->z
.port
),
2308 afs_inet_ntoa_r(haddr
, hoststr
),
2311 * add then remove. otherwise the host may get marked
2312 * deleted if we removed the only valid address.
2314 addInterfaceAddr_r(oldHost
, haddr
, hport
);
2315 if (probefail
|| oldHost
->z
.host
== haddr
) {
2317 * The probe failed which means that the old
2318 * address is either unreachable or is not the
2319 * same host we were just contacted by. We will
2320 * also remove addresses if only the port has
2321 * changed because that indicates the client
2324 removeInterfaceAddr_r(oldHost
, oldHost
->z
.host
, oldHost
->z
.port
);
2327 struct Interface
*interface
= oldHost
->z
.interface
;
2328 int number
= oldHost
->z
.interface
->numberOfInterfaces
;
2329 for (i
= 0; i
< number
; i
++) {
2330 if (interface
->interface
[i
].addr
== haddr
&&
2331 interface
->interface
[i
].port
!= hport
) {
2333 * We have just been contacted by a client
2334 * that has been seen from behind a NAT
2335 * and at least one other address.
2337 removeInterfaceAddr_r(oldHost
, haddr
,
2338 interface
->interface
[i
].port
);
2343 oldHost
->z
.host
= haddr
;
2344 oldHost
->z
.port
= hport
;
2345 rxconn
= oldHost
->z
.callback_rxcon
;
2346 oldHost
->z
.callback_rxcon
= host
->z
.callback_rxcon
;
2347 host
->z
.callback_rxcon
= rxconn
;
2349 /* don't destroy rxconn here; let h_TossStuff_r
2350 * take care of that via h_Release_r below */
2352 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
2354 /* release host because it was allocated by h_Alloc_r */
2357 /* the new host is held and locked */
2359 /* This really is a new host */
2360 opr_Assert(interfValid
== 1);
2361 initInterfaceAddr_r(host
, &interf
);
2363 cb_conn
= host
->z
.callback_rxcon
;
2364 rx_GetConnection(cb_conn
);
2367 RXAFSCB_InitCallBackState3(cb_conn
,
2369 rx_PutConnection(cb_conn
);
2374 ("InitCallBackState3 success on host %" AFS_PTR_FMT
" (%s:%d)\n",
2375 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2376 ntohs(host
->z
.port
)));
2382 ("CB: RCallBackConnectBack failed for %" AFS_PTR_FMT
" (%s:%d)\n",
2383 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
2384 host
->z
.hostFlags
|= VENUSDOWN
;
2387 ("CB: RCallBackConnectBack succeeded for %" AFS_PTR_FMT
" (%s:%d)\n",
2388 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
)));
2389 host
->z
.hostFlags
|= RESETDONE
;
2392 if (caps
.Capabilities_val
2393 && (caps
.Capabilities_val
[0] & CLIENT_CAPABILITY_ERRORTRANS
))
2394 host
->z
.hostFlags
|= HERRORTRANS
;
2396 host
->z
.hostFlags
&= ~(HERRORTRANS
);
2397 host
->z
.hostFlags
|= ALTADDR
; /* host structure initialization complete */
2398 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
2403 if (caps
.Capabilities_val
)
2404 free(caps
.Capabilities_val
);
2405 caps
.Capabilities_val
= NULL
;
2406 caps
.Capabilities_len
= 0;
2408 rx_DestroyConnection(cb_in
);
2418 h_InitHostPackage(int hquota
)
2420 opr_Assert(hquota
> 0);
2421 h_quota_limit
= hquota
;
2423 memset(&nulluuid
, 0, sizeof(afsUUID
));
2424 rxcon_ident_key
= rx_KeyCreate((rx_destructor_t
) free
);
2425 rxcon_client_key
= rx_KeyCreate((rx_destructor_t
) 0);
2426 opr_mutex_init(&host_glock_mutex
);
2430 MapName_r(char *uname
, afs_int32
* aval
)
2436 lnames
.namelist_len
= 1;
2437 lnames
.namelist_val
= (prname
*) uname
;
2438 lids
.idlist_len
= 0;
2439 lids
.idlist_val
= NULL
;
2442 code
= hpr_NameToId(&lnames
, &lids
);
2445 if (lids
.idlist_val
) {
2446 *aval
= lids
.idlist_val
[0];
2447 if (*aval
== AnonymousID
) {
2449 ("MapName: NameToId on %s returns anonymousID\n",
2450 lnames
.namelist_val
[0]));
2452 free(lids
.idlist_val
); /* return parms are not malloced in stub if server proc aborts */
2455 ("MapName: NameToId on '%s' is unknown\n",
2456 lnames
.namelist_val
[0]));
2467 PerHost_EnumerateClient(struct host
*host
, void *arock
)
2469 struct enumclient_args
*args
= arock
;
2470 struct client
*client
;
2473 for (client
= host
->z
.FirstClient
; client
; client
= client
->z
.next
) {
2474 if (!client
->z
.deleted
&& client
->z
.ViceId
== args
->vid
) {
2476 client
->z
.refCount
++;
2479 code
= (*args
->proc
)(client
, args
->rock
);
2482 h_ReleaseClient_r(client
);
2485 return H_ENUMERATE_BAIL(0);
2494 h_EnumerateClients(VolumeId vid
,
2495 int (*proc
)(struct client
*client
, void *rock
),
2498 struct enumclient_args args
;
2504 h_Enumerate_r(PerHost_EnumerateClient
, hostList
, &args
);
2509 format_vname(char *vname
, int usize
, const char *tname
, const char *tinst
,
2510 const char *tcell
, afs_int32 islocal
)
2514 len
= strlcpy(vname
, tname
, usize
);
2518 len
= strlcat(vname
, ".", usize
);
2521 len
= strlcat(vname
, tinst
, usize
);
2525 if (tcell
[0] && !islocal
) {
2526 len
= strlcat(vname
, "@", usize
);
2529 len
= strlcat(vname
, tcell
, usize
);
2537 getPeerDetails(struct rx_connection
*conn
,
2538 afs_int32
*viceid
, afs_int32
*expTime
, int authClass
)
2541 #if (64-MAXKTCNAMELEN)
2542 ticket name length
!= 64
2546 char tcell
[MAXKTCREALMLEN
];
2547 char uname
[PR_MAXNAMELEN
];
2549 *viceid
= AnonymousID
;
2550 *expTime
= 0x7fffffff;
2553 ("FindClient: authenticating connection: authClass=%d\n",
2555 if (authClass
== RX_SECIDX_VAB
) {
2556 /* A bcrypt tickets, no longer supported */
2557 ViceLog(1, ("FindClient: bcrypt ticket, using AnonymousID\n"));
2561 if (authClass
== RX_SECIDX_KAD
) {
2562 /* an rxkad ticket */
2566 /* kerberos ticket */
2567 code
= rxkad_GetServerInfo(conn
, /*level */ 0, (afs_uint32
*)expTime
,
2568 tname
, tinst
, tcell
, &kvno
);
2570 ViceLog(1, ("Failed to get rxkad ticket info\n"));
2575 ("FindClient: rxkad conn: name=%s,inst=%s,cell=%s,exp=%d,kvno=%d\n",
2576 tname
, tinst
, tcell
, *expTime
, kvno
));
2577 code
= afsconf_IsLocalRealmMatch(confDir
, &islocal
, tname
, tinst
, tcell
);
2580 ViceLog(0, ("FindClient: local realm check failed; code=%d", code
));
2584 code
= format_vname(uname
, sizeof(uname
), tname
, tinst
, tcell
, islocal
);
2586 ViceLog(0, ("FindClient: uname truncated."));
2590 /* translate the name to a vice id */
2591 code
= MapName_r(uname
, viceid
);
2593 ViceLog(1, ("failed to map name=%s -> code=%d\n", uname
,
2595 return code
; /* Actually flag this is a failure */
2605 * Called by the server main loop. Returns a h_Held client, which must be
2606 * released later the main loop. Allocates a client if the matching one
2607 * isn't around. The client is returned with its reference count incremented
2608 * by one. The caller must call h_ReleaseClient_r when finished with
2611 * The refCount on client->z.host is returned incremented. h_ReleaseClient_r
2612 * does not decrement the refCount on client->z.host.
2614 * *a_viceid is set to the user's ViceId, even if we don't return a client
2618 h_FindClient_r(struct rx_connection
*tcon
, afs_int32
*a_viceid
)
2620 struct client
*client
;
2621 struct host
*host
= NULL
;
2622 struct client
*oldClient
;
2623 afs_int32 viceid
= 0;
2631 client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2632 if (client
&& client
->z
.sid
== rx_GetConnectionId(tcon
)
2633 && client
->z
.VenusEpoch
== rx_GetConnectionEpoch(tcon
)
2634 && !(client
->z
.host
->z
.hostFlags
& HOSTDELETED
)
2635 && !client
->z
.deleted
) {
2638 *a_viceid
= client
->z
.ViceId
;
2640 client
->z
.refCount
++;
2641 h_Hold_r(client
->z
.host
);
2642 if (client
->z
.prfail
!= 2) {
2643 /* Could add shared lock on client here */
2644 /* note that we don't have to lock entry in this path to
2645 * ensure CPS is initialized, since we don't call rx_SetSpecific
2646 * until initialization is done, and we only get here if
2647 * rx_GetSpecific located the client structure.
2652 ObtainWriteLock(&client
->lock
); /* released at end */
2658 authClass
= rx_SecurityClassOf(tcon
);
2660 code
= getPeerDetails(tcon
, &viceid
, &expTime
, authClass
);
2668 if (!client
) { /* loop */
2669 host
= h_GetHost_r(tcon
); /* Returns with incremented refCount */
2675 /* First try to find the client structure */
2676 for (client
= host
->z
.FirstClient
; client
; client
= client
->z
.next
) {
2677 if (!client
->z
.deleted
&& (client
->z
.sid
== rx_GetConnectionId(tcon
))
2678 && (client
->z
.VenusEpoch
== rx_GetConnectionEpoch(tcon
))) {
2679 client
->z
.refCount
++;
2681 ObtainWriteLock(&client
->lock
);
2687 /* Still no client structure - get one */
2690 if (host
->z
.hostFlags
& HOSTDELETED
) {
2695 /* Retry to find the client structure */
2696 for (client
= host
->z
.FirstClient
; client
; client
= client
->z
.next
) {
2697 if (!client
->z
.deleted
&& (client
->z
.sid
== rx_GetConnectionId(tcon
))
2698 && (client
->z
.VenusEpoch
== rx_GetConnectionEpoch(tcon
))) {
2700 goto retryfirstclient
;
2705 ObtainWriteLock(&client
->lock
);
2706 client
->z
.refCount
= 1;
2707 client
->z
.host
= host
;
2708 client
->z
.InSameNetwork
= host
->z
.InSameNetwork
;
2709 client
->z
.ViceId
= viceid
;
2710 client
->z
.expTime
= expTime
; /* rx only */
2711 client
->z
.authClass
= authClass
; /* rx only */
2712 client
->z
.sid
= rx_GetConnectionId(tcon
);
2713 client
->z
.VenusEpoch
= rx_GetConnectionEpoch(tcon
);
2714 client
->z
.CPS
.prlist_val
= NULL
;
2715 client
->z
.CPS
.prlist_len
= 0;
2719 client
->z
.prfail
= fail
;
2721 if (!(client
->z
.CPS
.prlist_val
) || (viceid
!= client
->z
.ViceId
)) {
2722 client
->z
.CPS
.prlist_len
= 0;
2723 if (client
->z
.CPS
.prlist_val
&& (client
->z
.ViceId
!= ANONYMOUSID
))
2724 free(client
->z
.CPS
.prlist_val
);
2725 client
->z
.CPS
.prlist_val
= NULL
;
2726 client
->z
.ViceId
= viceid
;
2727 client
->z
.expTime
= expTime
;
2729 if (viceid
== ANONYMOUSID
) {
2730 client
->z
.CPS
.prlist_len
= AnonCPS
.prlist_len
;
2731 client
->z
.CPS
.prlist_val
= AnonCPS
.prlist_val
;
2734 code
= hpr_GetCPS(viceid
, &client
->z
.CPS
);
2739 ("pr_GetCPS failed(%d) for user %d, host %" AFS_PTR_FMT
" (%s:%d)\n",
2740 code
, viceid
, client
->z
.host
,
2741 afs_inet_ntoa_r(client
->z
.host
->z
.host
,hoststr
),
2742 ntohs(client
->z
.host
->z
.port
)));
2744 /* Although ubik_Call (called by pr_GetCPS) traverses thru
2745 * all protection servers and reevaluates things if no
2746 * sync server or quorum is found we could still end up
2747 * with one of these errors. In such case we would like to
2748 * reevaluate the rpc call to find if there's cps for this
2749 * guy. We treat other errors (except network failures
2750 * ones - i.e. code < 0) as an indication that there is no
2751 * CPS for this host. Ideally we could like to deal this
2752 * problem the other way around (i.e. if code == NOCPS
2753 * ignore else retry next time) but the problem is that
2754 * there're other errors (i.e. EPERM) for which we don't
2755 * want to retry and we don't know the whole code list!
2757 if (code
< 0 || code
== UNOQUORUM
|| code
== UNOTSYNC
)
2758 client
->z
.prfail
= 1;
2761 /* the disabling of system:administrators is so iffy and has so many
2762 * possible failure modes that we will disable it again */
2763 /* Turn off System:Administrator for safety
2764 * if (AL_IsAMember(SystemId, client->z.CPS) == 0)
2765 * osi_Assert(AL_DisableGroup(SystemId, client->z.CPS) == 0); */
2768 /* Now, tcon may already be set to a rock, since we blocked with no host
2769 * or client locks set above in pr_GetCPS (XXXX some locking is probably
2770 * required). So, before setting the RPC's rock, we should disconnect
2771 * the RPC from the other client structure's rock.
2773 oldClient
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2774 if (oldClient
&& oldClient
!= client
2775 && oldClient
->z
.sid
== rx_GetConnectionId(tcon
)
2776 && oldClient
->z
.VenusEpoch
== rx_GetConnectionEpoch(tcon
)
2777 && !(oldClient
->z
.host
->z
.hostFlags
& HOSTDELETED
)) {
2779 if (!oldClient
->z
.deleted
) {
2780 /* if we didn't create it, it's not ours to put back */
2782 ViceLog(0, ("FindClient: stillborn client %p(%x); "
2783 "conn %p (host %s:%d) had client %p(%x)\n",
2784 client
, client
->z
.sid
, tcon
,
2785 afs_inet_ntoa_r(rxr_HostOf(tcon
), hoststr
),
2786 ntohs(rxr_PortOf(tcon
)),
2787 oldClient
, oldClient
->z
.sid
));
2788 if ((client
->z
.ViceId
!= ANONYMOUSID
) && client
->z
.CPS
.prlist_val
)
2789 free(client
->z
.CPS
.prlist_val
);
2790 client
->z
.CPS
.prlist_val
= NULL
;
2791 client
->z
.CPS
.prlist_len
= 0;
2793 /* We should perhaps check for 0 here */
2794 client
->z
.refCount
--;
2795 ReleaseWriteLock(&client
->lock
);
2800 oldClient
->z
.refCount
++;
2802 h_Hold_r(oldClient
->z
.host
);
2803 h_Release_r(client
->z
.host
);
2806 ObtainWriteLock(&oldClient
->lock
);
2809 host
= oldClient
->z
.host
;
2811 ViceLog(0, ("FindClient: deleted client %p(%x ref %d host %p href "
2812 "%d) already had conn %p (host %s:%d, cid %x), stolen "
2813 "by client %p(%x, ref %d host %p href %d)\n",
2814 oldClient
, oldClient
->z
.sid
, oldClient
->z
.refCount
,
2815 oldClient
->z
.host
, oldClient
->z
.host
->z
.refCount
, tcon
,
2816 afs_inet_ntoa_r(rxr_HostOf(tcon
), hoststr
),
2817 ntohs(rxr_PortOf(tcon
)), rx_GetConnectionId(tcon
),
2818 client
, client
->z
.sid
, client
->z
.refCount
,
2819 client
->z
.host
, client
->z
.host
->z
.refCount
));
2820 /* rx_SetSpecific will be done immediately below */
2823 /* Avoid chaining in more than once. */
2827 if (host
->z
.hostFlags
& HOSTDELETED
) {
2832 client
->z
.host
= NULL
;
2834 if ((client
->z
.ViceId
!= ANONYMOUSID
) && client
->z
.CPS
.prlist_val
)
2835 free(client
->z
.CPS
.prlist_val
);
2836 client
->z
.CPS
.prlist_val
= NULL
;
2837 client
->z
.CPS
.prlist_len
= 0;
2839 client
->z
.refCount
--;
2840 ReleaseWriteLock(&client
->lock
);
2845 client
->z
.next
= host
->z
.FirstClient
;
2846 host
->z
.FirstClient
= client
;
2848 CurrentConnections
++; /* increment number of connections */
2850 rx_SetSpecific(tcon
, rxcon_client_key
, client
);
2851 ReleaseWriteLock(&client
->lock
);
2855 } /*h_FindClient_r */
2858 h_ReleaseClient_r(struct client
*client
)
2860 opr_Assert(client
->z
.refCount
> 0);
2861 client
->z
.refCount
--;
2867 * Sigh: this one is used to get the client AGAIN within the individual
2868 * server routines. This does not bother h_Holding the host, since
2869 * this is assumed already have been done by the server main loop.
2870 * It does check tokens, since only the server routines can return the
2871 * VICETOKENDEAD error code
2874 GetClient(struct rx_connection
*tcon
, struct client
**cp
)
2876 struct client
*client
;
2881 client
= (struct client
*)rx_GetSpecific(tcon
, rxcon_client_key
);
2882 if (client
== NULL
) {
2884 ("GetClient: no client in conn %p (host %s:%d), VBUSYING\n",
2885 tcon
, afs_inet_ntoa_r(rxr_HostOf(tcon
), hoststr
),
2886 ntohs(rxr_PortOf(tcon
))));
2890 if (rx_GetConnectionId(tcon
) != client
->z
.sid
2891 || rx_GetConnectionEpoch(tcon
) != client
->z
.VenusEpoch
) {
2893 ("GetClient: tcon %p tcon sid %d client sid %d\n",
2894 tcon
, rx_GetConnectionId(tcon
), client
->z
.sid
));
2898 if (client
&& client
->z
.LastCall
> client
->z
.expTime
&& client
->z
.expTime
) {
2900 ("Token for %s at %s:%d expired %d\n", h_UserName(client
),
2901 afs_inet_ntoa_r(client
->z
.host
->z
.host
, hoststr
),
2902 ntohs(client
->z
.host
->z
.port
), client
->z
.expTime
));
2904 return VICETOKENDEAD
;
2906 if (client
->z
.deleted
) {
2907 ViceLog(0, ("GetClient: got deleted client, connection will appear "
2908 "anonymous; tcon %p cid %x client %p ref %d host %p "
2909 "(%s:%d) href %d ViceId %d\n",
2910 tcon
, rx_GetConnectionId(tcon
), client
, client
->z
.refCount
,
2912 afs_inet_ntoa_r(client
->z
.host
->z
.host
, hoststr
),
2913 (int)ntohs(client
->z
.host
->z
.port
), client
->z
.host
->z
.refCount
,
2914 (int)client
->z
.ViceId
));
2917 client
->z
.refCount
++;
2924 PutClient(struct client
**cp
)
2930 h_ReleaseClient_r(*cp
);
2937 /* Client user name for short term use. Note that this is NOT inexpensive */
2939 h_UserName(struct client
*client
)
2941 static char User
[PR_MAXNAMELEN
+ 1];
2945 lids
.idlist_len
= 1;
2946 lids
.idlist_val
= malloc(1 * sizeof(afs_int32
));
2947 if (!lids
.idlist_val
) {
2948 ViceLogThenPanic(0, ("Failed malloc in h_UserName\n"));
2950 lnames
.namelist_len
= 0;
2951 lnames
.namelist_val
= (prname
*) 0;
2952 lids
.idlist_val
[0] = client
->z
.ViceId
;
2953 if (hpr_IdToName(&lids
, &lnames
)) {
2954 /* We need to free id we alloced above! */
2955 free(lids
.idlist_val
);
2956 return "*UNKNOWN USER NAME*";
2958 strncpy(User
, lnames
.namelist_val
[0], PR_MAXNAMELEN
);
2959 free(lids
.idlist_val
);
2960 free(lnames
.namelist_val
);
2969 ("Total Client entries = %d, blocks = %d; Host entries = %d, blocks = %d\n",
2970 CEs
, CEBlocks
, HTs
, HTBlocks
));
2976 h_PrintClient(struct host
*host
, void *rock
)
2978 StreamHandle_t
*file
= (StreamHandle_t
*)rock
;
2979 struct client
*client
;
2984 time_t LastCall
, expTime
;
2988 LastCall
= host
->z
.LastCall
;
2989 if (host
->z
.hostFlags
& HOSTDELETED
) {
2993 strftime(tbuffer
, sizeof(tbuffer
), "%a %b %d %H:%M:%S %Y",
2994 localtime_r(&LastCall
, &tm
));
2995 snprintf(tmpStr
, sizeof tmpStr
, "Host %s:%d down = %d, LastCall %s\n",
2996 afs_inet_ntoa_r(host
->z
.host
, hoststr
),
2997 ntohs(host
->z
.port
), (host
->z
.hostFlags
& VENUSDOWN
),
2999 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3000 for (client
= host
->z
.FirstClient
; client
; client
= client
->z
.next
) {
3001 if (!client
->z
.deleted
) {
3002 expTime
= client
->z
.expTime
;
3003 strftime(tbuffer
, sizeof(tbuffer
), "%a %b %d %H:%M:%S %Y",
3004 localtime_r(&expTime
, &tm
));
3005 snprintf(tmpStr
, sizeof tmpStr
,
3006 " user id=%d, name=%s, sl=%s till %s\n",
3007 client
->z
.ViceId
, h_UserName(client
),
3008 client
->z
.authClass
? "Authenticated"
3009 : "Not authenticated",
3010 client
->z
.authClass
? tbuffer
: "No Limit");
3011 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3012 snprintf(tmpStr
, sizeof tmpStr
, " CPS-%d is [",
3013 client
->z
.CPS
.prlist_len
);
3014 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3015 if (client
->z
.CPS
.prlist_val
) {
3016 for (i
= 0; i
< client
->z
.CPS
.prlist_len
; i
++) {
3017 snprintf(tmpStr
, sizeof tmpStr
, " %d",
3018 client
->z
.CPS
.prlist_val
[i
]);
3019 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3022 sprintf(tmpStr
, "]\n");
3023 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3029 } /*h_PrintClient */
3034 * Print a list of clients, with last security level and token value seen,
3038 h_PrintClients(void)
3045 StreamHandle_t
*file
= STREAM_OPEN(AFSDIR_SERVER_CLNTDUMP_FILEPATH
, "w");
3049 ("Couldn't create client dump file %s\n",
3050 AFSDIR_SERVER_CLNTDUMP_FILEPATH
));
3054 strftime(tbuffer
, sizeof(tbuffer
), "%a %b %d %H:%M:%S %Y",
3055 localtime_r(&now
, &tm
));
3056 snprintf(tmpStr
, sizeof tmpStr
, "List of active users at %s\n\n",
3058 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3059 h_Enumerate(h_PrintClient
, (char *)file
);
3060 STREAM_REALLYCLOSE(file
);
3061 ViceLog(0, ("Created client dump %s\n", AFSDIR_SERVER_CLNTDUMP_FILEPATH
));
3068 h_DumpHost(struct host
*host
, void *rock
)
3070 StreamHandle_t
*file
= (StreamHandle_t
*)rock
;
3077 snprintf(tmpStr
, sizeof tmpStr
,
3078 "ip:%s port:%d hidx:%d cbid:%d lock:%x last:%u active:%u "
3079 "down:%d del:%d cons:%d cldel:%d\n\t hpfailed:%d hcpsCall:%u "
3081 afs_inet_ntoa_r(host
->z
.host
, hoststr
), ntohs(host
->z
.port
),
3082 host
->index
, host
->z
.cblist
, CheckLock(&host
->lock
),
3083 host
->z
.LastCall
, host
->z
.ActiveCall
, (host
->z
.hostFlags
& VENUSDOWN
),
3084 host
->z
.hostFlags
& HOSTDELETED
, host
->z
.Console
,
3085 host
->z
.hostFlags
& CLIENTDELETED
, host
->z
.hcpsfailed
,
3087 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3088 if (host
->z
.hcps
.prlist_val
)
3089 for (i
= 0; i
< host
->z
.hcps
.prlist_len
; i
++) {
3090 snprintf(tmpStr
, sizeof tmpStr
, " %d", host
->z
.hcps
.prlist_val
[i
]);
3091 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3093 sprintf(tmpStr
, "] [");
3094 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3095 if (host
->z
.interface
)
3096 for (i
= 0; i
< host
->z
.interface
->numberOfInterfaces
; i
++) {
3098 sprintf(tmpStr
, " %s:%d",
3099 afs_inet_ntoa_r(host
->z
.interface
->interface
[i
].addr
, hoststr
),
3100 ntohs(host
->z
.interface
->interface
[i
].port
));
3101 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3103 sprintf(tmpStr
, "] refCount:%d hostFlags:%hu\n", host
->z
.refCount
, host
->z
.hostFlags
);
3104 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3116 StreamHandle_t
*file
= STREAM_OPEN(AFSDIR_SERVER_HOSTDUMP_FILEPATH
, "w");
3123 ("Couldn't create host dump file %s\n",
3124 AFSDIR_SERVER_HOSTDUMP_FILEPATH
));
3128 strftime(tbuffer
, sizeof(tbuffer
), "%a %b %d %H:%M:%S %Y",
3129 localtime_r(&now
, &tm
));
3130 snprintf(tmpStr
, sizeof tmpStr
, "List of active hosts at %s\n\n", tbuffer
);
3131 (void)STREAM_WRITE(tmpStr
, strlen(tmpStr
), 1, file
);
3132 h_Enumerate(h_DumpHost
, (char *)file
);
3133 STREAM_REALLYCLOSE(file
);
3134 ViceLog(0, ("Created host dump %s\n", AFSDIR_SERVER_HOSTDUMP_FILEPATH
));
3138 #ifdef AFS_DEMAND_ATTACH_FS
3141 * host state serialization
3143 static int h_stateFillHeader(struct host_state_header
* hdr
);
3144 static int h_stateCheckHeader(struct host_state_header
* hdr
);
3145 static int h_stateAllocMap(struct fs_dump_state
* state
);
3146 static int h_stateSaveHost(struct host
* host
, void *rock
);
3147 static int h_stateRestoreHost(struct fs_dump_state
* state
);
3148 static int h_stateRestoreIndex(struct host
* h
, void *rock
);
3149 static int h_stateVerifyHost(struct host
* h
, void *rock
);
3150 static int h_stateVerifyAddrHash(struct fs_dump_state
* state
, struct host
* h
,
3151 afs_uint32 addr
, afs_uint16 port
, int valid
);
3152 static int h_stateVerifyUuidHash(struct fs_dump_state
* state
, struct host
* h
);
3153 static void h_hostToDiskEntry_r(struct host
* in
, struct hostDiskEntry
* out
);
3154 static void h_diskEntryToHost_r(struct hostDiskEntry
* in
, struct host
* out
);
3157 * Is this host busy?
3159 * This is just a hint and should not be trusted; this should probably only be
3160 * used by the host state serialization code when trying to detect if a host
3161 * can be sanely serialized to disk or not. If this function returns 1, the
3162 * host may be in an invalid state and thus should not be saved to disk.
3165 h_isBusy_r(struct host
*host
)
3167 struct Lock
*hostLock
= &host
->lock
;
3170 LOCK_LOCK(hostLock
);
3171 if (hostLock
->excl_locked
|| hostLock
->readers_reading
) {
3174 LOCK_UNLOCK(hostLock
);
3180 if (hostBusyFlags(host
->z
.hostFlags
)) {
3187 /* this procedure saves all host state to disk for fast startup */
3189 h_stateSave(struct fs_dump_state
* state
)
3191 AssignInt64(state
->eof_offset
, &state
->hdr
->h_offset
);
3194 ViceLog(0, ("h_stateSave: hostCount=%d\n", hostCount
));
3196 /* invalidate host state header */
3197 memset(state
->h_hdr
, 0, sizeof(struct host_state_header
));
3199 if (fs_stateWriteHeader(state
, &state
->hdr
->h_offset
, state
->h_hdr
,
3200 sizeof(struct host_state_header
))) {
3205 fs_stateIncEOF(state
, sizeof(struct host_state_header
));
3207 h_Enumerate_r(h_stateSaveHost
, hostList
, (char *)state
);
3212 h_stateFillHeader(state
->h_hdr
);
3214 /* write the real header to disk */
3215 state
->bail
= fs_stateWriteHeader(state
, &state
->hdr
->h_offset
, state
->h_hdr
,
3216 sizeof(struct host_state_header
));
3223 * host state serialization
3225 * this procedure restores all host state from a disk for fast startup
3228 h_stateRestore(struct fs_dump_state
* state
)
3232 /* seek to the right position and read in the host state header */
3233 if (fs_stateReadHeader(state
, &state
->hdr
->h_offset
, state
->h_hdr
,
3234 sizeof(struct host_state_header
))) {
3239 /* check the validity of the header */
3240 if (h_stateCheckHeader(state
->h_hdr
)) {
3245 records
= state
->h_hdr
->records
;
3247 if (h_stateAllocMap(state
)) {
3252 /* iterate over records restoring host state */
3253 for (i
=0; i
< records
; i
++) {
3254 if (h_stateRestoreHost(state
) != 0) {
3265 h_stateRestoreIndices(struct fs_dump_state
* state
)
3267 h_Enumerate_r(h_stateRestoreIndex
, hostList
, (char *)state
);
3272 h_stateRestoreIndex(struct host
* h
, void *rock
)
3274 struct fs_dump_state
*state
= (struct fs_dump_state
*)rock
;
3275 if (cb_OldToNew(state
, h
->z
.cblist
, &h
->z
.cblist
)) {
3276 return H_ENUMERATE_BAIL(0);
3282 h_stateVerify(struct fs_dump_state
* state
)
3284 h_Enumerate_r(h_stateVerifyHost
, hostList
, (char *)state
);
3289 h_stateVerifyHost(struct host
* h
, void* rock
)
3291 struct fs_dump_state
*state
= (struct fs_dump_state
*)rock
;
3295 ViceLog(0, ("h_stateVerifyHost: error: NULL host pointer in linked list\n"));
3296 return H_ENUMERATE_BAIL(0);
3299 if (h
->z
.interface
) {
3300 for (i
= h
->z
.interface
->numberOfInterfaces
-1; i
>= 0; i
--) {
3301 if (h_stateVerifyAddrHash(state
, h
, h
->z
.interface
->interface
[i
].addr
,
3302 h
->z
.interface
->interface
[i
].port
,
3303 h
->z
.interface
->interface
[i
].valid
)) {
3307 if (h_stateVerifyUuidHash(state
, h
)) {
3310 } else if (h_stateVerifyAddrHash(state
, h
, h
->z
.host
, h
->z
.port
, 1)) {
3314 if (cb_stateVerifyHCBList(state
, h
)) {
3322 * verify a host is either in, or absent from, the addr hash table.
3324 * @param[in] state fs dump state
3325 * @param[in] h host we're dealing with
3326 * @param[in] addr addr to look for (NBO)
3327 * @param[in] port port to look for (NBO)
3328 * @param[in] valid 1 if we're verifying that the specified addr and port
3329 * in the hash table point to the specified host. 0 if we're
3330 * verifying that the specified addr and port do NOT point
3331 * to the specified host
3333 * @return operation status
3334 * @retval 1 failed to verify, bail out
3335 * @retval 0 verified successfully, all is well
3338 h_stateVerifyAddrHash(struct fs_dump_state
* state
, struct host
* h
,
3339 afs_uint32 addr
, afs_uint16 port
, int valid
)
3341 int ret
= 0, found
= 0;
3342 struct host
*host
= NULL
;
3343 struct h_AddrHashChain
*chain
;
3344 int index
= h_HashIndex(addr
);
3348 for (chain
= hostAddrHashTable
[index
]; chain
; chain
= chain
->next
) {
3349 host
= chain
->hostPtr
;
3351 afs_inet_ntoa_r(addr
, tmp
);
3352 ViceLog(0, ("h_stateVerifyAddrHash: error: addr hash chain has NULL host ptr (lookup addr %s)\n", tmp
));
3356 if ((chain
->addr
== addr
) && (chain
->port
== port
)) {
3359 ViceLog(0, ("h_stateVerifyAddrHash: warning: addr hash entry "
3360 "points to different host struct (%d, %d)\n",
3361 h
->index
, host
->index
));
3362 state
->flags
.warnings_generated
= 1;
3366 ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s:%u is "
3367 "marked invalid, but points to the containing "
3368 "host\n", afs_inet_ntoa_r(addr
, tmp
),
3369 (unsigned)htons(port
)));
3377 if (chain_len
> FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN
) {
3378 ViceLog(0, ("h_stateVerifyAddrHash: error: hash chain length exceeds %d; assuming there's a loop\n",
3379 FS_STATE_H_MAX_ADDR_HASH_CHAIN_LEN
));
3386 if (!found
&& valid
) {
3387 afs_inet_ntoa_r(addr
, tmp
);
3388 if (state
->mode
== FS_STATE_LOAD_MODE
) {
3389 ViceLog(0, ("h_stateVerifyAddrHash: error: addr %s:%u not found in hash\n",
3390 tmp
, (unsigned)htons(port
)));
3394 ViceLog(0, ("h_stateVerifyAddrHash: warning: addr %s:%u not found in hash\n",
3395 tmp
, (unsigned)htons(port
)));
3396 state
->flags
.warnings_generated
= 1;
3405 h_stateVerifyUuidHash(struct fs_dump_state
* state
, struct host
* h
)
3408 struct host
*host
= NULL
;
3409 struct h_UuidHashChain
*chain
;
3410 afsUUID
* uuidp
= &h
->z
.interface
->uuid
;
3411 int index
= h_UuidHashIndex(uuidp
);
3415 for (chain
= hostUuidHashTable
[index
]; chain
; chain
= chain
->next
) {
3416 host
= chain
->hostPtr
;
3418 afsUUID_to_string(uuidp
, tmp
, sizeof(tmp
));
3419 ViceLog(0, ("h_stateVerifyUuidHash: error: uuid hash chain has NULL host ptr (lookup uuid %s)\n", tmp
));
3423 if (host
->z
.interface
&&
3424 afs_uuid_equal(&host
->z
.interface
->uuid
, uuidp
)) {
3426 ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid hash entry points to different host struct (%d, %d)\n",
3427 h
->index
, host
->index
));
3428 state
->flags
.warnings_generated
= 1;
3432 if (chain_len
> FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN
) {
3433 ViceLog(0, ("h_stateVerifyUuidHash: error: hash chain length exceeds %d; assuming there's a loop\n",
3434 FS_STATE_H_MAX_UUID_HASH_CHAIN_LEN
));
3441 /* Fall through, so host not found */
3443 afsUUID_to_string(uuidp
, tmp
, sizeof(tmp
));
3444 if (state
->mode
== FS_STATE_LOAD_MODE
) {
3445 ViceLog(0, ("h_stateVerifyUuidHash: error: uuid %s not found in hash\n", tmp
));
3449 ViceLog(0, ("h_stateVerifyUuidHash: warning: uuid %s not found in hash\n", tmp
));
3450 state
->flags
.warnings_generated
= 1;
3457 /* create the host state header structure */
3459 h_stateFillHeader(struct host_state_header
* hdr
)
3461 hdr
->stamp
.magic
= HOST_STATE_MAGIC
;
3462 hdr
->stamp
.version
= HOST_STATE_VERSION
;
3466 /* check the contents of the host state header structure */
3468 h_stateCheckHeader(struct host_state_header
* hdr
)
3472 if (hdr
->stamp
.magic
!= HOST_STATE_MAGIC
) {
3473 ViceLog(0, ("check_host_state_header: invalid state header\n"));
3476 else if (hdr
->stamp
.version
!= HOST_STATE_VERSION
) {
3477 ViceLog(0, ("check_host_state_header: unknown version number\n"));
3483 /* allocate the host id mapping table */
3485 h_stateAllocMap(struct fs_dump_state
* state
)
3487 state
->h_map
.len
= state
->h_hdr
->index_max
+ 1;
3488 state
->h_map
.entries
= (struct idx_map_entry_t
*)
3489 calloc(state
->h_map
.len
, sizeof(struct idx_map_entry_t
));
3490 return (state
->h_map
.entries
!= NULL
) ? 0 : 1;
3493 /* function called by h_Enumerate to save a host to disk */
3495 h_stateSaveHost(struct host
* host
, void* rock
)
3497 struct fs_dump_state
*state
= (struct fs_dump_state
*) rock
;
3498 int if_len
=0, hcps_len
=0;
3499 struct hostDiskEntry hdsk
;
3500 struct host_state_entry_header hdr
;
3501 struct Interface
* ifp
= NULL
;
3502 afs_int32
* hcps
= NULL
;
3503 struct iovec iov
[4];
3506 if (h_isBusy_r(host
)) {
3508 ViceLog(1, ("Not saving host %s:%d to disk; host appears busy\n",
3509 afs_inet_ntoa_r(host
->z
.host
, hoststr
), (int)ntohs(host
->z
.port
)));
3510 /* Make sure we don't try to save callbacks to disk for this host, or
3511 * we'll get confused on restore */
3512 DeleteAllCallBacks_r(host
, 1);
3516 memset(&hdr
, 0, sizeof(hdr
));
3518 if (state
->h_hdr
->index_max
< host
->index
) {
3519 state
->h_hdr
->index_max
= host
->index
;
3522 h_hostToDiskEntry_r(host
, &hdsk
);
3523 if (host
->z
.interface
) {
3524 if_len
= sizeof(struct Interface
) +
3525 ((host
->z
.interface
->numberOfInterfaces
-1) * sizeof(struct AddrPort
));
3526 ifp
= malloc(if_len
);
3527 opr_Assert(ifp
!= NULL
);
3528 memcpy(ifp
, host
->z
.interface
, if_len
);
3529 hdr
.interfaces
= host
->z
.interface
->numberOfInterfaces
;
3530 iov
[iovcnt
].iov_base
= (char *) ifp
;
3531 iov
[iovcnt
].iov_len
= if_len
;
3534 if (host
->z
.hcps
.prlist_val
) {
3535 hdr
.hcps
= host
->z
.hcps
.prlist_len
;
3536 hcps_len
= hdr
.hcps
* sizeof(afs_int32
);
3537 hcps
= malloc(hcps_len
);
3538 opr_Assert(hcps
!= NULL
);
3539 memcpy(hcps
, host
->z
.hcps
.prlist_val
, hcps_len
);
3540 iov
[iovcnt
].iov_base
= (char *) hcps
;
3541 iov
[iovcnt
].iov_len
= hcps_len
;
3545 if (hdsk
.index
> state
->h_hdr
->index_max
)
3546 state
->h_hdr
->index_max
= hdsk
.index
;
3548 hdr
.len
= sizeof(struct host_state_entry_header
) +
3549 sizeof(struct hostDiskEntry
) + if_len
+ hcps_len
;
3550 hdr
.magic
= HOST_STATE_ENTRY_MAGIC
;
3552 iov
[0].iov_base
= (char *) &hdr
;
3553 iov
[0].iov_len
= sizeof(hdr
);
3554 iov
[1].iov_base
= (char *) &hdsk
;
3555 iov
[1].iov_len
= sizeof(struct hostDiskEntry
);
3557 if (fs_stateWriteV(state
, iov
, iovcnt
)) {
3558 ViceLog(0, ("h_stateSaveHost: failed to save host %d", host
->index
));
3562 fs_stateIncEOF(state
, hdr
.len
);
3564 state
->h_hdr
->records
++;
3571 return H_ENUMERATE_BAIL(0);
3576 /* restores a host from disk */
3578 h_stateRestoreHost(struct fs_dump_state
* state
)
3580 int ifp_len
=0, hcps_len
=0, bail
=0;
3581 struct host_state_entry_header hdr
;
3582 struct hostDiskEntry hdsk
;
3583 struct host
*host
= NULL
;
3584 struct Interface
*ifp
= NULL
;
3585 afs_int32
* hcps
= NULL
;
3586 struct iovec iov
[3];
3589 if (fs_stateRead(state
, &hdr
, sizeof(hdr
))) {
3590 ViceLog(0, ("h_stateRestoreHost: failed to read host entry header from dump file '%s'\n",
3596 if (hdr
.magic
!= HOST_STATE_ENTRY_MAGIC
) {
3597 ViceLog(0, ("h_stateRestoreHost: fileserver state dump file '%s' is corrupt.\n",
3603 iov
[0].iov_base
= (char *) &hdsk
;
3604 iov
[0].iov_len
= sizeof(struct hostDiskEntry
);
3606 if (hdr
.interfaces
) {
3607 ifp_len
= sizeof(struct Interface
) +
3608 ((hdr
.interfaces
-1) * sizeof(struct AddrPort
));
3609 ifp
= malloc(ifp_len
);
3610 opr_Assert(ifp
!= NULL
);
3611 iov
[iovcnt
].iov_base
= (char *) ifp
;
3612 iov
[iovcnt
].iov_len
= ifp_len
;
3616 hcps_len
= hdr
.hcps
* sizeof(afs_int32
);
3617 hcps
= malloc(hcps_len
);
3618 opr_Assert(hcps
!= NULL
);
3619 iov
[iovcnt
].iov_base
= (char *) hcps
;
3620 iov
[iovcnt
].iov_len
= hcps_len
;
3624 if ((ifp_len
+ hcps_len
+ sizeof(hdsk
) + sizeof(hdr
)) != hdr
.len
) {
3625 ViceLog(0, ("h_stateRestoreHost: host entry header length fields are inconsistent\n"));
3630 if (fs_stateReadV(state
, iov
, iovcnt
)) {
3631 ViceLog(0, ("h_stateRestoreHost: failed to read host entry\n"));
3636 if (!hdr
.hcps
&& hdsk
.hcps_valid
) {
3637 /* valid, zero-length host cps ; does this ever happen? */
3638 hcps
= malloc(sizeof(afs_int32
));
3639 opr_Assert(hcps
!= NULL
);
3642 if (hostBusyFlags(hdsk
.hostFlags
)) {
3644 ViceLog(0, ("h_stateRestoreHost: skipping host %s:%d due to invalid flags 0x%x\n",
3645 afs_inet_ntoa_r(hdsk
.host
, hoststr
), (int)ntohs(hdsk
.port
),
3646 (unsigned)hdsk
.hostFlags
));
3648 state
->h_map
.entries
[hdsk
.index
].valid
= FS_STATE_IDX_SKIPPED
;
3652 /* for restoring state, we better be able to get a host! */
3654 opr_Assert(host
!= NULL
);
3657 host
->z
.interface
= ifp
;
3660 host
->z
.hcps
.prlist_val
= hcps
;
3661 host
->z
.hcps
.prlist_len
= hdr
.hcps
;
3664 h_diskEntryToHost_r(&hdsk
, host
);
3665 h_SetupCallbackConn_r(host
);
3667 h_AddHostToAddrHashTable_r(host
->z
.host
, host
->z
.port
, host
);
3670 for (i
= ifp
->numberOfInterfaces
-1; i
>= 0; i
--) {
3671 if (ifp
->interface
[i
].valid
&&
3672 !(ifp
->interface
[i
].addr
== host
->z
.host
&&
3673 ifp
->interface
[i
].port
== host
->z
.port
)) {
3674 h_AddHostToAddrHashTable_r(ifp
->interface
[i
].addr
,
3675 ifp
->interface
[i
].port
,
3679 h_AddHostToUuidHashTable_r(&ifp
->uuid
, host
);
3681 h_InsertList_r(host
);
3683 /* setup host id map entry */
3684 state
->h_map
.entries
[hdsk
.index
].valid
= FS_STATE_IDX_VALID
;
3685 state
->h_map
.entries
[hdsk
.index
].old_idx
= hdsk
.index
;
3686 state
->h_map
.entries
[hdsk
.index
].new_idx
= host
->index
;
3698 /* serialize a host structure to disk */
3700 h_hostToDiskEntry_r(struct host
* in
, struct hostDiskEntry
* out
)
3702 out
->host
= in
->z
.host
;
3703 out
->port
= in
->z
.port
;
3704 out
->hostFlags
= in
->z
.hostFlags
;
3705 out
->Console
= in
->z
.Console
;
3706 out
->hcpsfailed
= in
->z
.hcpsfailed
;
3707 out
->LastCall
= in
->z
.LastCall
;
3708 out
->ActiveCall
= in
->z
.ActiveCall
;
3709 out
->cpsCall
= in
->z
.cpsCall
;
3710 out
->cblist
= in
->z
.cblist
;
3711 out
->InSameNetwork
= in
->z
.InSameNetwork
;
3713 /* special fields we save, but are not memcpy'd back on restore */
3714 out
->index
= in
->index
;
3715 out
->hcps_len
= in
->z
.hcps
.prlist_len
;
3716 out
->hcps_valid
= (in
->z
.hcps
.prlist_val
== NULL
) ? 0 : 1;
3719 /* restore a host structure from disk */
3721 h_diskEntryToHost_r(struct hostDiskEntry
* in
, struct host
* out
)
3723 out
->z
.host
= in
->host
;
3724 out
->z
.port
= in
->port
;
3725 out
->z
.hostFlags
= in
->hostFlags
;
3726 out
->z
.Console
= in
->Console
;
3727 out
->z
.hcpsfailed
= in
->hcpsfailed
;
3728 out
->z
.LastCall
= in
->LastCall
;
3729 out
->z
.ActiveCall
= in
->ActiveCall
;
3730 out
->z
.cpsCall
= in
->cpsCall
;
3731 out
->z
.cblist
= in
->cblist
;
3732 out
->z
.InSameNetwork
= in
->InSameNetwork
;
3735 /* index translation routines */
3737 h_OldToNew(struct fs_dump_state
* state
, afs_uint32 old
, afs_uint32
* new)
3741 /* hosts use a zero-based index, so old==0 is valid */
3743 if (old
>= state
->h_map
.len
) {
3744 ViceLog(0, ("h_OldToNew: index %d is out of range\n", old
));
3746 } else if (state
->h_map
.entries
[old
].valid
!= FS_STATE_IDX_VALID
||
3747 state
->h_map
.entries
[old
].old_idx
!= old
) { /* sanity check */
3748 ViceLog(0, ("h_OldToNew: index %d points to an invalid host record\n", old
));
3751 *new = state
->h_map
.entries
[old
].new_idx
;
3756 #endif /* AFS_DEMAND_ATTACH_FS */
3760 * This counts the number of workstations, the number of active workstations,
3761 * and the number of workstations declared "down" (i.e. not heard from
3762 * recently). An active workstation has received a call since the cutoff
3763 * time argument passed.
3766 h_GetWorkStats(int *nump
, int *activep
, int *delp
, afs_int32 cutofftime
)
3769 int num
= 0, active
= 0, del
= 0;
3773 for (count
= 0, host
= hostList
; host
&& count
< hostCount
; host
= host
->z
.next
, count
++) {
3774 if (!(host
->z
.hostFlags
& HOSTDELETED
)) {
3776 if (host
->z
.ActiveCall
> cutofftime
)
3778 if (host
->z
.hostFlags
& VENUSDOWN
)
3782 if (count
!= hostCount
) {
3783 ViceLog(0, ("h_GetWorkStats found %d of %d hosts\n", count
, hostCount
));
3784 } else if (host
!= NULL
) {
3785 ViceLog(0, ("h_GetWorkStats found more than %d hosts\n", hostCount
));
3786 ShutDownAndCore(PANIC
);
3796 } /*h_GetWorkStats */
3799 h_GetWorkStats64(afs_uint64
*nump
, afs_uint64
*activep
, afs_uint64
*delp
,
3800 afs_int32 cutofftime
)
3802 int num
, active
, del
;
3803 h_GetWorkStats(&num
, &active
, &del
, cutofftime
);
3812 /*------------------------------------------------------------------------
3813 * PRIVATE h_ClassifyAddress
3816 * Given a target IP address and a candidate IP address (both
3817 * in host byte order), classify the candidate into one of three
3818 * buckets in relation to the target by bumping the counters passed
3822 * a_targetAddr : Target address.
3823 * a_candAddr : Candidate address.
3824 * a_sameNetOrSubnetP : Ptr to counter to bump when the two
3825 * addresses are either in the same network
3826 * or the same subnet.
3827 * a_diffSubnetP : ...when the candidate is in a different
3829 * a_diffNetworkP : ...when the candidate is in a different
3836 * The target and candidate addresses are both in host byte
3837 * order, NOT network byte order, when passed in.
3841 *------------------------------------------------------------------------*/
3844 h_ClassifyAddress(afs_uint32 a_targetAddr
, afs_uint32 a_candAddr
,
3845 afs_int32
* a_sameNetOrSubnetP
, afs_int32
* a_diffSubnetP
,
3846 afs_int32
* a_diffNetworkP
)
3847 { /*h_ClassifyAddress */
3849 afs_uint32 targetNet
;
3850 afs_uint32 targetSubnet
;
3852 afs_uint32 candSubnet
;
3855 * Put bad values into the subnet info to start with.
3857 targetSubnet
= (afs_uint32
) 0;
3858 candSubnet
= (afs_uint32
) 0;
3861 * Pull out the network and subnetwork numbers from the target
3862 * and candidate addresses. We can short-circuit this whole
3863 * affair if the target and candidate addresses are not of the
3866 if (IN_CLASSA(a_targetAddr
)) {
3867 if (!(IN_CLASSA(a_candAddr
))) {
3868 (*a_diffNetworkP
)++;
3871 targetNet
= a_targetAddr
& IN_CLASSA_NET
;
3872 candNet
= a_candAddr
& IN_CLASSA_NET
;
3873 if (IN_SUBNETA(a_targetAddr
))
3874 targetSubnet
= a_targetAddr
& IN_CLASSA_SUBNET
;
3875 if (IN_SUBNETA(a_candAddr
))
3876 candSubnet
= a_candAddr
& IN_CLASSA_SUBNET
;
3877 } else if (IN_CLASSB(a_targetAddr
)) {
3878 if (!(IN_CLASSB(a_candAddr
))) {
3879 (*a_diffNetworkP
)++;
3882 targetNet
= a_targetAddr
& IN_CLASSB_NET
;
3883 candNet
= a_candAddr
& IN_CLASSB_NET
;
3884 if (IN_SUBNETB(a_targetAddr
))
3885 targetSubnet
= a_targetAddr
& IN_CLASSB_SUBNET
;
3886 if (IN_SUBNETB(a_candAddr
))
3887 candSubnet
= a_candAddr
& IN_CLASSB_SUBNET
;
3888 } /*Class B target */
3889 else if (IN_CLASSC(a_targetAddr
)) {
3890 if (!(IN_CLASSC(a_candAddr
))) {
3891 (*a_diffNetworkP
)++;
3894 targetNet
= a_targetAddr
& IN_CLASSC_NET
;
3895 candNet
= a_candAddr
& IN_CLASSC_NET
;
3898 * Note that class C addresses can't have subnets,
3899 * so we leave the defaults untouched.
3901 } /*Class C target */
3903 targetNet
= a_targetAddr
;
3904 candNet
= a_candAddr
;
3905 } /*Class D address */
3908 * Now, simply compare the extracted net and subnet values for
3909 * the two addresses (which at this point are known to be of the
3912 if (targetNet
== candNet
) {
3913 if (targetSubnet
== candSubnet
)
3914 (*a_sameNetOrSubnetP
)++;
3918 (*a_diffNetworkP
)++;
3920 } /*h_ClassifyAddress */
3923 /*------------------------------------------------------------------------
3924 * EXPORTED h_GetHostNetStats
3927 * Iterate through the host table, and classify each (non-deleted)
3928 * host entry into ``proximity'' categories (same net or subnet,
3929 * different subnet, different network).
3932 * a_numHostsP : Set to total number of (non-deleted) hosts.
3933 * a_sameNetOrSubnetP : Set to # hosts on same net/subnet as server.
3934 * a_diffSubnetP : Set to # hosts on diff subnet as server.
3935 * a_diffNetworkP : Set to # hosts on diff network as server.
3941 * We only count non-deleted hosts. The storage pointed to by our
3942 * parameters is zeroed upon entry.
3946 *------------------------------------------------------------------------*/
3949 h_GetHostNetStats(afs_int32
* a_numHostsP
, afs_int32
* a_sameNetOrSubnetP
,
3950 afs_int32
* a_diffSubnetP
, afs_int32
* a_diffNetworkP
)
3951 { /*h_GetHostNetStats */
3953 struct host
*hostP
; /*Ptr to current host entry */
3954 afs_uint32 currAddr_HBO
; /*Curr host addr, host byte order */
3958 * Clear out the storage pointed to by our parameters.
3960 *a_numHostsP
= (afs_int32
) 0;
3961 *a_sameNetOrSubnetP
= (afs_int32
) 0;
3962 *a_diffSubnetP
= (afs_int32
) 0;
3963 *a_diffNetworkP
= (afs_int32
) 0;
3966 for (count
= 0, hostP
= hostList
; hostP
&& count
< hostCount
; hostP
= hostP
->z
.next
, count
++) {
3967 if (!(hostP
->z
.hostFlags
& HOSTDELETED
)) {
3969 * Bump the number of undeleted host entries found.
3970 * In classifying the current entry's address, make
3971 * sure to first convert to host byte order.
3974 currAddr_HBO
= (afs_uint32
) ntohl(hostP
->z
.host
);
3975 h_ClassifyAddress(FS_HostAddr_HBO
, currAddr_HBO
,
3976 a_sameNetOrSubnetP
, a_diffSubnetP
,
3978 } /*Only look at non-deleted hosts */
3979 } /*For each host record hashed to this index */
3980 if (count
!= hostCount
) {
3981 ViceLog(0, ("h_GetHostNetStats found %d of %d hosts\n", count
, hostCount
));
3982 } else if (hostP
!= NULL
) {
3983 ViceLog(0, ("h_GetHostNetStats found more than %d hosts\n", hostCount
));
3984 ShutDownAndCore(PANIC
);
3987 } /*h_GetHostNetStats */
3989 static afs_uint32 checktime
;
3990 static afs_uint32 clientdeletetime
;
3991 static struct AFSFid zerofid
;
3995 * XXXX: This routine could use Multi-Rx to avoid serializing the timeouts.
3996 * Since it can serialize them, and pile up, it should be a separate LWP
3997 * from other events.
4001 CheckHost_r(struct host
*host
, void *dummy
)
4003 struct client
*client
;
4004 struct rx_connection
*cb_conn
= NULL
;
4007 #ifdef AFS_DEMAND_ATTACH_FS
4008 /* kill the checkhost lwp ASAP during shutdown */
4010 if (fs_state
.mode
== FS_MODE_SHUTDOWN
) {
4012 return H_ENUMERATE_BAIL(0);
4017 /* Host is held by h_Enumerate_r */
4018 for (client
= host
->z
.FirstClient
; client
; client
= client
->z
.next
) {
4019 if (client
->z
.refCount
== 0 && client
->z
.LastCall
< clientdeletetime
) {
4020 client
->z
.deleted
= 1;
4021 host
->z
.hostFlags
|= CLIENTDELETED
;
4024 if (host
->z
.LastCall
< checktime
) {
4026 if (!(host
->z
.hostFlags
& HOSTDELETED
)) {
4027 host
->z
.hostFlags
|= HWHO_INPROGRESS
;
4028 cb_conn
= host
->z
.callback_rxcon
;
4029 rx_GetConnection(cb_conn
);
4030 if (host
->z
.LastCall
< clientdeletetime
) {
4031 host
->z
.hostFlags
|= HOSTDELETED
;
4032 if (!(host
->z
.hostFlags
& VENUSDOWN
)) {
4033 host
->z
.hostFlags
&= ~ALTADDR
; /* alternate address invalid */
4034 if (host
->z
.interface
) {
4037 RXAFSCB_InitCallBackState3(cb_conn
,
4043 RXAFSCB_InitCallBackState(cb_conn
);
4046 host
->z
.hostFlags
|= ALTADDR
; /* alternate addresses valid */
4049 (void)afs_inet_ntoa_r(host
->z
.host
, hoststr
);
4051 ("CB: RCallBackConnectBack (host.c) failed for host %s:%d\n",
4052 hoststr
, ntohs(host
->z
.port
)));
4053 host
->z
.hostFlags
|= VENUSDOWN
;
4055 /* Note: it's safe to delete hosts even if they have call
4056 * back state, because break delayed callbacks (called when a
4057 * message is received from the workstation) will always send a
4058 * break all call backs to the workstation if there is no
4063 if (!(host
->z
.hostFlags
& VENUSDOWN
) && host
->z
.cblist
) {
4065 (void)afs_inet_ntoa_r(host
->z
.host
, hoststr
);
4066 if (host
->z
.interface
) {
4067 afsUUID uuid
= host
->z
.interface
->uuid
;
4069 code
= RXAFSCB_ProbeUuid(cb_conn
, &uuid
);
4072 if (MultiProbeAlternateAddress_r(host
)) {
4073 ViceLog(0,("CheckHost_r: Probing all interfaces of host %s:%d failed, code %d\n",
4074 hoststr
, ntohs(host
->z
.port
), code
));
4075 host
->z
.hostFlags
|= VENUSDOWN
;
4080 code
= RXAFSCB_Probe(cb_conn
);
4084 ("CheckHost_r: Probe failed for host %s:%d, code %d\n",
4085 hoststr
, ntohs(host
->z
.port
), code
));
4086 host
->z
.hostFlags
|= VENUSDOWN
;
4092 rx_PutConnection(cb_conn
);
4095 host
->z
.hostFlags
&= ~HWHO_INPROGRESS
;
4105 * Set VenusDown for any hosts that have not had a call in 15 minutes and
4106 * don't respond to a probe. Note that VenusDown can only be cleared if
4107 * a message is received from the host (see ServerLWP in file.c).
4108 * Delete hosts that have not had any calls in 1 hour, clients that
4109 * have not had any calls in 15 minutes.
4111 * This routine is called roughly every 5 minutes.
4116 afs_uint32 now
= time(NULL
);
4118 memset(&zerofid
, 0, sizeof(zerofid
));
4120 * Send a probe to the workstation if it hasn't been heard from in
4123 checktime
= now
- 15 * 60;
4124 clientdeletetime
= now
- 120 * 60; /* 2 hours ago */
4127 h_Enumerate_r(CheckHost_r
, hostList
, NULL
);
4132 * This is called with host locked and held. At this point, the
4133 * hostAddrHashTable has an entry for the primary addr/port inserted
4134 * by h_Alloc_r(). No other interfaces should be considered valid.
4136 * The addresses in the interfaceAddr list are in host byte order.
4139 initInterfaceAddr_r(struct host
*host
, struct interfaceAddr
*interf
)
4146 struct Interface
*interface
;
4149 afs_uint16 port7001
= htons(7001);
4154 number
= interf
->numberOfInterfaces
;
4155 myAddr
= host
->z
.host
; /* current interface address */
4156 myPort
= host
->z
.port
; /* current port */
4159 ("initInterfaceAddr : host %s:%d numAddr %d\n",
4160 afs_inet_ntoa_r(myAddr
, hoststr
), ntohs(myPort
), number
));
4162 /* validation checks */
4163 if (number
< 0 || number
> AFS_MAX_INTERFACE_ADDR
) {
4165 ("Invalid number of alternate addresses is %d\n", number
));
4170 * The client's notion of its own IP addresses is not reliable.
4172 * 1. The client list might contain private address ranges which
4173 * are likely to be re-used by many clients allocated addresses
4176 * 2. The client list will not include any public addresses that
4177 * are hidden by a NAT.
4179 * 3. Private address ranges that are exposed to the server will
4180 * be obtained from the rx connections that use them.
4182 * 4. Lists provided by the client are not necessarily truthful.
4183 * Many existing clients (UNIX) do not refresh the IP address
4184 * list as the actual assigned addresses change. The end result
4185 * is that they report the initial address list for the lifetime
4186 * of the process. In other words, a client can report addresses
4187 * that they are in fact not using. Adding these addresses to
4188 * the host interface list without verification is not only
4189 * pointless, it is downright dangerous.
4191 * We therefore do not add alternate addresses to the addr hash table.
4192 * We only use them for multi-rx callback breaks.
4196 * Convert IP addresses to network byte order, and remove
4197 * duplicate and loopback IP addresses from the interface list, and
4198 * determine whether or not the incoming addr/port is
4199 * listed. Note that if the address matches it is not
4200 * truly a match because the port number for the entries
4201 * in the interface list are port 7001 and the port number
4202 * for this connection might not be 7001.
4204 for (i
= 0, count
= 0, found
= 0; i
< number
; i
++) {
4205 if (rx_IsLoopbackAddr(interf
->addr_in
[i
])) {
4208 interf
->addr_in
[i
] = htonl(interf
->addr_in
[i
]);
4209 for (j
= 0; j
< count
; j
++) {
4210 if (interf
->addr_in
[j
] == interf
->addr_in
[i
])
4214 interf
->addr_in
[count
] = interf
->addr_in
[i
];
4215 if (interf
->addr_in
[count
] == myAddr
&&
4223 * Allocate and initialize an interface structure for this host.
4226 interface
= malloc(sizeof(struct Interface
) +
4227 (sizeof(struct AddrPort
) * (count
- 1)));
4229 ViceLogThenPanic(0, ("Failed malloc in initInterfaceAddr_r 1\n"));
4231 interface
->numberOfInterfaces
= count
;
4233 interface
= malloc(sizeof(struct Interface
) +
4234 (sizeof(struct AddrPort
) * count
));
4236 ViceLogThenPanic(0, ("Failed malloc in initInterfaceAddr_r 2\n"));
4238 interface
->numberOfInterfaces
= count
+ 1;
4239 interface
->interface
[count
].addr
= myAddr
;
4240 interface
->interface
[count
].port
= myPort
;
4241 interface
->interface
[count
].valid
= 1;
4244 for (i
= 0; i
< count
; i
++) {
4246 interface
->interface
[i
].addr
= interf
->addr_in
[i
];
4247 /* We store the port as 7001 because the addresses reported by
4248 * TellMeAboutYourself and WhoAreYou RPCs are only valid if they
4249 * are coming from fully connected hosts (no NAT/PATs)
4251 interface
->interface
[i
].port
= port7001
;
4252 interface
->interface
[i
].valid
=
4253 (interf
->addr_in
[i
] == myAddr
&& port7001
== myPort
) ? 1 : 0;
4256 interface
->uuid
= interf
->uuid
;
4258 opr_Assert(!host
->z
.interface
);
4259 host
->z
.interface
= interface
;
4261 h_AddHostToUuidHashTable_r(&interface
->uuid
, host
);
4263 if (GetLogLevel() >= 125) {
4264 afsUUID_to_string(&interface
->uuid
, uuidstr
, 127);
4266 ViceLog(125, ("--- uuid %s\n", uuidstr
));
4267 for (i
= 0; i
< host
->z
.interface
->numberOfInterfaces
; i
++) {
4268 ViceLog(125, ("--- alt address %s:%d\n",
4269 afs_inet_ntoa_r(host
->z
.interface
->interface
[i
].addr
, hoststr
),
4270 ntohs(host
->z
.interface
->interface
[i
].port
)));
4277 /* deleted a HashChain structure for this address and host */
4278 /* returns 1 on success */
4280 h_DeleteHostFromAddrHashTable_r(afs_uint32 addr
, afs_uint16 port
,
4284 struct h_AddrHashChain
**hp
, *th
;
4286 if (addr
== 0 && port
== 0)
4289 for (hp
= &hostAddrHashTable
[h_HashIndex(addr
)]; (th
= *hp
);
4291 opr_Assert(th
->hostPtr
);
4292 if (th
->hostPtr
== host
&& th
->addr
== addr
&& th
->port
== port
) {
4293 ViceLog(125, ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT
" (%s:%d)\n",
4294 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
4295 ntohs(host
->z
.port
)));
4302 ("h_DeleteHostFromAddrHashTable_r: host %" AFS_PTR_FMT
" (%s:%d) not found\n",
4303 host
, afs_inet_ntoa_r(host
->z
.host
, hoststr
),
4304 ntohs(host
->z
.port
)));
4310 ** prints out all alternate interface address for the host. The 'level'
4311 ** parameter indicates what level of debugging sets this output
4314 printInterfaceAddr(struct host
*host
, int level
)
4319 if (host
->z
.interface
) {
4320 /* check alternate addresses */
4321 number
= host
->z
.interface
->numberOfInterfaces
;
4323 ViceLog(level
, ("no-addresses "));
4325 for (i
= 0; i
< number
; i
++)
4326 ViceLog(level
, ("%s:%d ",
4327 afs_inet_ntoa_r(host
->z
.interface
->interface
[i
].addr
,
4329 ntohs(host
->z
.interface
->interface
[i
].port
)));
4332 ViceLog(level
, ("\n"));