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
13 #include <afsconfig.h>
14 #include "../afs/param.h"
18 #include "../afs/stds.h"
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
23 #include <netinet/in.h>
26 #include "../h/hashing.h"
28 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
29 #include <netinet/in_var.h>
30 #endif /* ! ASF_HPUX110_ENV */
31 #endif /* !defined(UKERNEL) */
33 #include "../afs/afsincludes.h" /* Afs-based standard headers */
34 #include "../afs/afs_stats.h" /* afs statistics */
36 #if defined(AFS_SUN56_ENV)
38 #include <inet/common.h>
39 #if defined(AFS_SUN58_ENV)
40 #include <netinet/ip6.h>
45 /* Exported variables */
46 afs_rwlock_t afs_xcell; /* allocation lock for cells */
48 afs_int32 afs_cellindex=0;
49 afs_int32 afs_realcellindex=0;
50 afs_uint32 afs_nextCellNum = 0x100;
52 /* Local variables. */
53 struct cell *afs_rootcell = 0;
55 /* Handler waiting for request from client */
56 static int afs_AfsdbHandlerWait;
57 /* Client waiting for handler to become available or finish request */
58 static int afs_AfsdbLookupWait;
60 /* Set to 1 when we've seen the userspace AFSDB process at least once */
61 char afs_AfsdbHandlerPresent = 0;
62 /* Set to 1 when there is a client interacting with the AFSDB handler.
63 * Protects the in and out variables below. Protected by GLOCK. */
64 char afs_AfsdbHandlerInuse = 0;
65 /* Set to 1 when AFSDB has been shut down */
66 char afs_AfsdbHandlerShutdown = 0;
68 /* Input to handler from the client: cell name to look up */
69 char *afs_AfsdbHandler_CellName;
70 /* Outputs from handler to client: cell hosts, TTL, and real cell name */
71 afs_int32 *afs_AfsdbHandler_CellHosts;
72 int *afs_AfsdbHandler_Timeout;
73 char **afs_AfsdbHandler_RealName;
75 /* Client sets ReqPending to 1 whenever it queues a request for it */
76 char afs_AfsdbHandler_ReqPending = 0;
77 /* Handler sets Completed to 1 when it completes the client request */
78 char afs_AfsdbHandler_Completed = 0;
80 int afs_strcasecmp(register char *s1, register char *s2)
87 if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
88 if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
98 void afs_StopAfsdb(void)
100 if (afs_AfsdbHandlerPresent) {
101 afs_osi_Wakeup(&afs_AfsdbHandlerWait);
103 afs_AfsdbHandlerShutdown = 1;
104 afs_termState = AFSOP_STOP_RXEVENT;
108 int afs_AfsdbHandler(char *acellName, int acellNameLen, afs_int32 *kernelMsg)
110 /* afs_syscall_call() has already grabbed the global lock */
112 if (afs_AfsdbHandlerShutdown) return -2;
113 afs_AfsdbHandlerPresent = 1;
115 if (afs_AfsdbHandler_ReqPending) {
118 hostCount = kernelMsg[0];
119 *afs_AfsdbHandler_Timeout = kernelMsg[1];
120 if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
122 *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
123 strcpy(*afs_AfsdbHandler_RealName, acellName);
125 for (i=0; i<MAXCELLHOSTS; i++) {
127 afs_AfsdbHandler_CellHosts[i] = 0;
129 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
132 /* Request completed, wake up the relevant thread */
133 afs_AfsdbHandler_ReqPending = 0;
134 afs_AfsdbHandler_Completed = 1;
135 afs_osi_Wakeup(&afs_AfsdbLookupWait);
138 /* Wait for a request */
139 while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
140 afs_osi_Sleep(&afs_AfsdbHandlerWait);
142 /* Check if we're shutting down */
143 if (afs_termState == AFSOP_STOP_AFSDB) {
144 /* Inform anyone waiting for us that we're going away */
145 afs_AfsdbHandlerShutdown = 1;
146 afs_AfsdbHandlerPresent = 0;
147 afs_osi_Wakeup(&afs_AfsdbLookupWait);
149 afs_termState = AFSOP_STOP_RXEVENT;
150 afs_osi_Wakeup(&afs_termState);
154 /* Copy the requested cell name into the request buffer */
155 strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
157 /* Return the lookup request to userspace */
163 int afs_GetCellHostsFromDns(char *acellName, afs_int32 *acellHosts,
164 int *timeout, char **realName)
169 if (!afs_AfsdbHandlerPresent) return ENOENT;
171 /* Initialize host list to empty in case the handler is gone */
174 if (!ISAFS_GLOCK()) {
179 /* Wait until the AFSDB handler is available, and grab it */
180 while (afs_AfsdbHandlerInuse)
181 afs_osi_Sleep(&afs_AfsdbLookupWait);
182 afs_AfsdbHandlerInuse = 1;
184 /* Set up parameters for the handler */
185 afs_AfsdbHandler_CellName = acellName;
186 afs_AfsdbHandler_CellHosts = acellHosts;
187 afs_AfsdbHandler_Timeout = timeout;
188 afs_AfsdbHandler_RealName = realName;
190 /* Wake up the AFSDB handler */
191 afs_AfsdbHandler_Completed = 0;
192 afs_AfsdbHandler_ReqPending = 1;
193 afs_osi_Wakeup(&afs_AfsdbHandlerWait);
195 /* Wait for the handler to get back to us with the reply */
196 while (afs_AfsdbHandlerPresent && !afs_AfsdbHandler_Completed)
197 afs_osi_Sleep(&afs_AfsdbLookupWait);
199 /* Release the AFSDB handler and wake up others waiting for it */
200 afs_AfsdbHandlerInuse = 0;
201 afs_osi_Wakeup(&afs_AfsdbLookupWait);
203 if (grab_glock) AFS_GUNLOCK();
205 if (*acellHosts) return 0;
213 void afs_RefreshCell(register struct cell *ac)
215 afs_int32 cellHosts[MAXCELLHOSTS];
216 char *realName = NULL;
220 if (ac->cellHosts[0]) /* If we already have some servers.. */
221 if (!ac->timeout || ac->timeout > osi_Time())
222 /* Don't refresh if not expired */
225 if (afs_GetCellHostsFromDns(ac->cellName, cellHosts, &timeout, &realName))
226 /* In case of lookup failure, keep old data */
229 /* Refresh the DB servers for the real cell; other values stay the same. */
230 afs_NewCell(realName, cellHosts, 0, NULL, 0, 0, timeout, NULL);
232 /* If this is an alias, update the alias entry too */
233 if (afs_strcasecmp(ac->cellName, realName)) {
235 * Look up the entry we just updated, to compensate for
236 * uppercase-vs-lowercase lossage with DNS.
238 tc = afs_FindCellByName(realName, READ_LOCK);
241 afs_NewCell(ac->cellName, 0, CAlias, NULL, 0, 0,
242 timeout, tc->cellName);
243 afs_PutCell(tc, READ_LOCK);
249 afs_osi_Free(realName, strlen(realName) + 1);
253 struct cell *afs_GetCellByName_Dns(register char *acellName, afs_int32 locktype)
255 afs_int32 cellHosts[MAXCELLHOSTS];
256 char *realName = NULL;
260 if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
262 if (afs_NewCell(realName, cellHosts, CNoSUID, NULL, 0, 0,
266 /* If this is an alias, create an entry for it too */
267 if (afs_strcasecmp(acellName, realName)) {
269 * Look up the entry we just updated, to compensate for
270 * uppercase-vs-lowercase lossage with DNS.
272 tc = afs_FindCellByName(realName, READ_LOCK);
276 if (afs_NewCell(acellName, 0, CAlias, NULL, 0, 0,
277 timeout, tc->cellName)) {
278 afs_PutCell(tc, READ_LOCK);
282 afs_PutCell(tc, READ_LOCK);
286 afs_osi_Free(realName, strlen(realName) + 1);
287 return afs_FindCellByName(acellName, locktype);
291 afs_osi_Free(realName, strlen(realName) + 1);
296 struct cell *afs_FindCellByName(register char *acellName, afs_int32 locktype)
298 register struct cell *tc;
299 register struct afs_q *cq, *tq;
302 AFS_STATCNT(afs_GetCellByName);
304 ObtainWriteLock(&afs_xcell,100);
305 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
306 tc = QTOC(cq); tq = QNext(cq);
307 if (!afs_strcasecmp(tc->cellName, acellName)) {
309 QAdd(&CellLRU, &tc->lruq);
310 ReleaseWriteLock(&afs_xcell);
312 if ((tc->states & CAlias) && (didAlias == 0)) {
313 acellName = tc->realName;
314 if (!acellName) return NULL;
322 ReleaseWriteLock(&afs_xcell);
326 struct cell *afs_GetCellByName(register char *acellName, afs_int32 locktype)
330 tc = afs_FindCellByName(acellName, locktype);
332 tc = afs_GetCellByName_Dns(acellName, locktype);
337 static struct cell *afs_GetCellInternal(register afs_int32 acell,
338 afs_int32 locktype, int holdxcell)
340 register struct cell *tc;
341 register struct afs_q *cq, *tq;
343 AFS_STATCNT(afs_GetCell);
344 if (acell == 1 && afs_rootcell) return afs_rootcell;
346 ObtainWriteLock(&afs_xcell,101);
347 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
348 tc = QTOC(cq); tq = QNext(cq);
349 if (tc->cell == acell) {
351 QAdd(&CellLRU, &tc->lruq);
353 ReleaseWriteLock(&afs_xcell);
359 ReleaseWriteLock(&afs_xcell);
364 struct cell *afs_GetCell(register afs_int32 acell, afs_int32 locktype)
366 return afs_GetCellInternal(acell, locktype, 1);
369 /* This is only to be called if the caller is already holding afs_xcell */
370 struct cell *afs_GetCellNoLock(register afs_int32 acell, afs_int32 locktype)
372 return afs_GetCellInternal(acell, locktype, 0);
375 struct cell *afs_GetCellByIndex(register afs_int32 cellindex,
376 afs_int32 locktype, afs_int32 refresh)
378 register struct cell *tc;
379 register struct afs_q *cq, *tq;
381 AFS_STATCNT(afs_GetCellByIndex);
382 ObtainWriteLock(&afs_xcell,102);
383 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
384 tc = QTOC(cq); tq = QNext(cq);
385 if (tc->cellIndex == cellindex) {
387 QAdd(&CellLRU, &tc->lruq);
388 ReleaseWriteLock(&afs_xcell);
389 if (refresh) afs_RefreshCell(tc);
393 ReleaseWriteLock(&afs_xcell);
399 struct cell *afs_GetRealCellByIndex(register afs_int32 cellindex, afs_int32 locktype, afs_int32 refresh)
401 register struct cell *tc;
402 register struct afs_q *cq, *tq;
404 AFS_STATCNT(afs_GetCellByIndex);
405 ObtainWriteLock(&afs_xcell,102);
406 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
407 tc = QTOC(cq); tq = QNext(cq);
408 if (tc->realcellIndex == cellindex) {
410 QAdd(&CellLRU, &tc->lruq);
411 ReleaseWriteLock(&afs_xcell);
412 if (refresh) afs_RefreshCell(tc);
416 ReleaseWriteLock(&afs_xcell);
418 } /*afs_GetRealCellByIndex*/
421 afs_int32 afs_NewCell(char *acellName, register afs_int32 *acellHosts, int aflags,
422 char *linkedcname, u_short fsport, u_short vlport, int timeout, char *aliasFor)
424 register struct cell *tc, *tcl=0;
425 register afs_int32 i, newc=0, code=0;
426 register struct afs_q *cq, *tq;
428 AFS_STATCNT(afs_NewCell);
430 ObtainWriteLock(&afs_xcell,103);
432 /* Find the cell and mark its servers as not down but gone */
433 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
434 tc = QTOC(cq); tq = QNext(cq);
435 if (afs_strcasecmp(tc->cellName, acellName) == 0) {
436 /* If the cell we've found has the correct name but no timeout,
437 * and we're called with a non-zero timeout, bail out: never
438 * override static configuration entries with AFSDB ones.
439 * One exception: if the original cell entry had no servers,
440 * it must get servers from AFSDB.
442 if (timeout && !tc->timeout && tc->cellHosts[0]) {
443 ReleaseWriteLock(&afs_xcell);
446 /* we don't want to keep pinging old vlservers which were down,
447 * since they don't matter any more. It's easier to do this than
448 * to remove the server from its various hash tables. */
449 for (i=0; i<MAXCELLHOSTS; i++) {
450 if (!tc->cellHosts[i]) break;
451 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
452 tc->cellHosts[i]->flags |= SRVR_ISGONE;
458 if (cq != &CellLRU) {
462 tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
463 memset((char *)tc, 0, sizeof(*tc));
464 QAdd(&CellLRU, &tc->lruq); /* put in lruq */
465 tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
466 strcpy(tc->cellName, acellName);
467 tc->cellIndex = afs_cellindex++;
468 if (aflags & CPrimary) {
469 extern int afs_rootCellIndex;
470 tc->cell = 1; /* primary cell is always 1 */
472 afs_rootCellIndex = tc->cellIndex;
474 tc->cell = afs_nextCellNum++;
478 tc->fsport = (fsport ? fsport : AFS_FSPORT);
479 tc->vlport = (vlport ? vlport : AFS_VLPORT);
480 afs_stats_cmperf.numCellsVisible++;
482 if (!(aflags & CAlias)) {
483 tc->realcellIndex = afs_realcellindex++;
485 tc->realcellIndex = -1;
489 if (aflags & CLinkedCell) {
494 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
495 tcl = QTOC(cq); tq = QNext(cq);
496 if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
505 if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */
506 tcl->lcellp->lcellp = NULL;
507 tcl->lcellp->states &= ~CLinkedCell;
512 tc->states |= aflags;
513 tc->timeout = timeout;
515 /* Allow converting an alias into a real cell */
516 if ((!(aflags & CAlias)) && (tc->states & CAlias)) {
517 tc->states &= ~CAlias;
518 tc->realcellIndex = afs_realcellindex++;
521 memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
522 if (aflags & CAlias) {
527 if (tc->realName) afs_osi_Free(tc->realName, strlen(tc->realName)+1);
528 tc->realName = (char *) afs_osi_Alloc(strlen(aliasFor)+1);
529 strcpy(tc->realName, aliasFor);
533 for (i=0; i<MAXCELLHOSTS; i++) {
535 afs_uint32 temp = acellHosts[i];
537 ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
539 ts->flags &= ~SRVR_ISGONE;
540 tc->cellHosts[i] = ts;
541 afs_PutServer(ts, WRITE_LOCK);
543 afs_SortServers(tc->cellHosts, MAXCELLHOSTS); /* randomize servers */
545 ReleaseWriteLock(&afs_xcell);
550 afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
551 afs_osi_Free((char *)tc, sizeof(struct cell));
553 ReleaseWriteLock(&afs_xcell);
557 void afs_RemoveCellEntry(struct server *srvp)
565 /* Remove the server structure from the cell list - if there */
566 ObtainWriteLock(&afs_xcell,200);
567 for (j=k=0; j<MAXCELLHOSTS; j++) {
568 if (!tc->cellHosts[j]) break;
569 if (tc->cellHosts[j] != srvp) {
570 tc->cellHosts[k++] = tc->cellHosts[j];
574 /* What do we do if we remove the last one? */
576 for (; k<MAXCELLHOSTS; k++) {
577 tc->cellHosts[k] = 0;
579 ReleaseWriteLock(&afs_xcell);