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)
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_uint32 afs_nextCellNum = 0x100;
52 /* Local variables. */
53 struct cell *afs_rootcell = 0;
55 /* Handler waiting for request from client */
56 static char afs_AfsdbHandlerWait;
57 /* Client waiting for handler to become available or finish request */
58 static char 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;
81 struct cell *afs_GetCellByName2();
83 int afs_strcasecmp(s1, s2)
84 register char *s1, *s2;
91 if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
92 if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
104 if (afs_AfsdbHandlerPresent) {
105 afs_osi_Wakeup(&afs_AfsdbHandlerWait);
107 afs_AfsdbHandlerShutdown = 1;
108 afs_termState = AFSOP_STOP_RXEVENT;
112 int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
115 afs_int32 *kernelMsg;
117 /* afs_syscall_call() has already grabbed the global lock */
119 if (afs_AfsdbHandlerShutdown) return -2;
120 afs_AfsdbHandlerPresent = 1;
122 if (afs_AfsdbHandler_ReqPending) {
125 hostCount = kernelMsg[0];
126 *afs_AfsdbHandler_Timeout = kernelMsg[1];
127 if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
129 *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
130 strcpy(*afs_AfsdbHandler_RealName, acellName);
132 for (i=0; i<MAXCELLHOSTS; i++) {
134 afs_AfsdbHandler_CellHosts[i] = 0;
136 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
139 /* Request completed, wake up the relevant thread */
140 afs_AfsdbHandler_ReqPending = 0;
141 afs_AfsdbHandler_Completed = 1;
142 afs_osi_Wakeup(&afs_AfsdbLookupWait);
145 /* Wait for a request */
146 while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
147 afs_osi_Sleep(&afs_AfsdbHandlerWait);
149 /* Check if we're shutting down */
150 if (afs_termState == AFSOP_STOP_AFSDB) {
151 /* Inform anyone waiting for us that we're going away */
152 afs_AfsdbHandlerShutdown = 1;
153 afs_AfsdbHandlerPresent = 0;
154 afs_osi_Wakeup(&afs_AfsdbLookupWait);
156 afs_termState = AFSOP_STOP_RXEVENT;
157 afs_osi_Wakeup(&afs_termState);
161 /* Copy the requested cell name into the request buffer */
162 strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
164 /* Return the lookup request to userspace */
170 int afs_GetCellHostsFromDns(acellName, acellHosts, timeout, realName)
172 afs_int32 *acellHosts;
179 if (!afs_AfsdbHandlerPresent) return ENOENT;
181 /* Initialize host list to empty in case the handler is gone */
184 if (!ISAFS_GLOCK()) {
189 /* Wait until the AFSDB handler is available, and grab it */
190 while (afs_AfsdbHandlerInuse)
191 afs_osi_Sleep(&afs_AfsdbLookupWait);
192 afs_AfsdbHandlerInuse = 1;
194 /* Set up parameters for the handler */
195 afs_AfsdbHandler_CellName = acellName;
196 afs_AfsdbHandler_CellHosts = acellHosts;
197 afs_AfsdbHandler_Timeout = timeout;
198 afs_AfsdbHandler_RealName = realName;
200 /* Wake up the AFSDB handler */
201 afs_AfsdbHandler_Completed = 0;
202 afs_AfsdbHandler_ReqPending = 1;
203 afs_osi_Wakeup(&afs_AfsdbHandlerWait);
205 /* Wait for the handler to get back to us with the reply */
206 while (afs_AfsdbHandlerPresent && !afs_AfsdbHandler_Completed)
207 afs_osi_Sleep(&afs_AfsdbLookupWait);
209 /* Release the AFSDB handler and wake up others waiting for it */
210 afs_AfsdbHandlerInuse = 0;
211 afs_osi_Wakeup(&afs_AfsdbLookupWait);
213 if (grab_glock) AFS_GUNLOCK();
215 if (*acellHosts) return 0;
223 void afs_RefreshCell(ac)
224 register struct cell *ac;
226 afs_int32 cellHosts[MAXCELLHOSTS];
227 char *realName = NULL;
231 /* Don't need to do anything if no timeout or it's not expired */
232 if (!ac->timeout || ac->timeout > osi_Time()) return;
234 if (afs_GetCellHostsFromDns(ac->cellName, cellHosts, &timeout, &realName))
235 /* In case of lookup failure, keep old data */
238 /* Refresh the DB servers for the real cell; other values stay the same. */
239 afs_NewCell(realName, cellHosts, 0, (char *) 0, 0, 0, timeout, (char *) 0);
241 /* If this is an alias, update the alias entry too */
242 if (afs_strcasecmp(ac->cellName, realName)) {
244 * Look up the entry we just updated, to compensate for
245 * uppercase-vs-lowercase lossage with DNS.
247 tc = afs_GetCellByName2(realName, READ_LOCK, 0 /* no AFSDB */);
250 afs_NewCell(ac->cellName, 0, CAlias, (char *) 0, 0, 0,
251 timeout, tc->cellName);
252 afs_PutCell(tc, READ_LOCK);
258 afs_osi_Free(realName, strlen(realName) + 1);
262 struct cell *afs_GetCellByName_Dns(acellName, locktype)
263 register char *acellName;
266 afs_int32 cellHosts[MAXCELLHOSTS];
267 char *realName = NULL;
271 if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
273 if (afs_NewCell(realName, cellHosts, CNoSUID, (char *) 0, 0, 0,
274 timeout, (char *) 0))
277 /* If this is an alias, create an entry for it too */
278 if (afs_strcasecmp(acellName, realName)) {
280 * Look up the entry we just updated, to compensate for
281 * uppercase-vs-lowercase lossage with DNS.
283 tc = afs_GetCellByName2(realName, READ_LOCK, 0 /* no AFSDB */);
287 if (afs_NewCell(acellName, 0, CAlias, (char *) 0, 0, 0,
288 timeout, tc->cellName)) {
289 afs_PutCell(tc, READ_LOCK);
293 afs_PutCell(tc, READ_LOCK);
297 afs_osi_Free(realName, strlen(realName) + 1);
298 return afs_GetCellByName2(acellName, locktype, 0);
302 afs_osi_Free(realName, strlen(realName) + 1);
303 return (struct cell *) 0;
307 struct cell *afs_GetCellByName2(acellName, locktype, trydns)
308 register char *acellName;
312 register struct cell *tc;
313 register struct afs_q *cq, *tq;
316 AFS_STATCNT(afs_GetCellByName);
318 ObtainWriteLock(&afs_xcell,100);
319 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
320 tc = QTOC(cq); tq = QNext(cq);
321 if (!afs_strcasecmp(tc->cellName, acellName)) {
323 QAdd(&CellLRU, &tc->lruq);
324 ReleaseWriteLock(&afs_xcell);
326 if ((tc->states & CAlias) && (didAlias == 0)) {
327 acellName = tc->realName;
328 if (!acellName) return (struct cell *) 0;
335 ReleaseWriteLock(&afs_xcell);
336 return trydns ? afs_GetCellByName_Dns(acellName, locktype)
339 } /*afs_GetCellByName2*/
342 struct cell *afs_GetCellByName(acellName, locktype)
343 register char *acellName;
346 return afs_GetCellByName2(acellName, locktype, 1);
348 } /*afs_GetCellByName*/
351 struct cell *afs_GetCell(acell, locktype)
352 register afs_int32 acell;
355 register struct cell *tc;
356 register struct afs_q *cq, *tq;
358 AFS_STATCNT(afs_GetCell);
359 if (acell == 1 && afs_rootcell) return afs_rootcell;
360 ObtainWriteLock(&afs_xcell,101);
361 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
362 tc = QTOC(cq); tq = QNext(cq);
363 if (tc->cell == acell) {
365 QAdd(&CellLRU, &tc->lruq);
366 ReleaseWriteLock(&afs_xcell);
371 ReleaseWriteLock(&afs_xcell);
372 return (struct cell *) 0;
377 struct cell *afs_GetCellByIndex(cellindex, locktype, refresh)
378 register afs_int32 cellindex;
382 register struct cell *tc;
383 register struct afs_q *cq, *tq;
385 AFS_STATCNT(afs_GetCellByIndex);
386 ObtainWriteLock(&afs_xcell,102);
387 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
388 tc = QTOC(cq); tq = QNext(cq);
389 if (tc->cellIndex == cellindex) {
391 QAdd(&CellLRU, &tc->lruq);
392 ReleaseWriteLock(&afs_xcell);
393 if (refresh) afs_RefreshCell(tc);
397 ReleaseWriteLock(&afs_xcell);
398 return (struct cell *) 0;
400 } /*afs_GetCellByIndex*/
403 afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout, aliasFor)
406 register afs_int32 *acellHosts;
408 u_short fsport, vlport;
412 register struct cell *tc, *tcl=0;
413 register afs_int32 i, newc=0, code=0;
414 register struct afs_q *cq, *tq;
416 AFS_STATCNT(afs_NewCell);
417 if (!(aflags & CAlias) && *acellHosts == 0)
418 /* need >= one host to gen cell # */
421 ObtainWriteLock(&afs_xcell,103);
423 /* Find the cell and mark its servers as not down but gone */
424 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
425 tc = QTOC(cq); tq = QNext(cq);
426 if (afs_strcasecmp(tc->cellName, acellName) == 0) {
427 /* if the cell we've found has the correct name but no timeout,
428 * and we're called with a non-zero timeout, bail out: never
429 * override static configuration entries with AFSDB ones. */
430 if (timeout && !tc->timeout) {
431 ReleaseWriteLock(&afs_xcell);
434 /* we don't want to keep pinging old vlservers which were down,
435 * since they don't matter any more. It's easier to do this than
436 * to remove the server from its various hash tables. */
437 for (i=0; i<MAXCELLHOSTS; i++) {
438 if (!tc->cellHosts[i]) break;
439 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
440 tc->cellHosts[i]->flags |= SRVR_ISGONE;
446 if (cq != &CellLRU) {
450 tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
451 memset((char *)tc, 0, sizeof(*tc));
452 QAdd(&CellLRU, &tc->lruq); /* put in lruq */
453 tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
454 strcpy(tc->cellName, acellName);
455 tc->cellIndex = afs_cellindex++;
456 if (aflags & CPrimary) {
457 extern int afs_rootCellIndex;
458 tc->cell = 1; /* primary cell is always 1 */
460 afs_rootCellIndex = tc->cellIndex;
462 tc->cell = afs_nextCellNum++;
465 tc->lcellp = (struct cell *)0;
466 tc->fsport = (fsport ? fsport : AFS_FSPORT);
467 tc->vlport = (vlport ? vlport : AFS_VLPORT);
468 afs_stats_cmperf.numCellsVisible++;
472 if (aflags & CLinkedCell) {
477 for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
478 tcl = QTOC(cq); tq = QNext(cq);
479 if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
488 if (tcl->lcellp) { /* XXX Overwriting if one existed before! XXX */
489 tcl->lcellp->lcellp = (struct cell *)0;
490 tcl->lcellp->states &= ~CLinkedCell;
495 tc->states |= aflags;
496 tc->timeout = timeout;
498 /* Allow converting an alias into a real cell */
499 if (!(aflags & CAlias)) tc->states &= ~CAlias;
501 memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
502 if (aflags & CAlias) {
507 if (tc->realName) afs_osi_Free(tc->realName, strlen(tc->realName)+1);
508 tc->realName = (char *) afs_osi_Alloc(strlen(aliasFor)+1);
509 strcpy(tc->realName, aliasFor);
513 for (i=0; i<MAXCELLHOSTS; i++) {
515 afs_uint32 temp = acellHosts[i];
517 ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
519 ts->flags &= ~SRVR_ISGONE;
520 tc->cellHosts[i] = ts;
521 afs_PutServer(ts, WRITE_LOCK);
523 afs_SortServers(tc->cellHosts, MAXCELLHOSTS); /* randomize servers */
525 ReleaseWriteLock(&afs_xcell);
530 afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
531 afs_osi_Free((char *)tc, sizeof(struct cell));
533 ReleaseWriteLock(&afs_xcell);
538 afs_RemoveCellEntry(struct server *srvp)
546 /* Remove the server structure from the cell list - if there */
547 ObtainWriteLock(&afs_xcell,200);
548 for (j=k=0; j<MAXCELLHOSTS; j++) {
549 if (!tc->cellHosts[j]) break;
550 if (tc->cellHosts[j] != srvp) {
551 tc->cellHosts[k++] = tc->cellHosts[j];
555 /* What do we do if we remove the last one? */
557 for (; k<MAXCELLHOSTS; k++) {
558 tc->cellHosts[k] = 0;
560 ReleaseWriteLock(&afs_xcell);