u_short vlport; /* volume server port */
short states; /* state flags */
short cellIndex; /* relative index number per cell */
+ time_t timeout; /* data expire time, if non-zero */
};
#define afs_PutCell(cellp, locktype)
AFS_COPYIN((char *)parm3, tcell.cellName, parm4, code);
if (!code)
afs_NewCell(tcell.cellName, tcell.hosts, parm5,
- (char *)0, (u_short)0, (u_short)0);
+ (char *)0, (u_short)0, (u_short)0, (int)0);
}
}
} else if (parm == AFSOP_ADDCELL2) {
}
if (!code)
afs_NewCell(tbuffer1, tcell.hosts, cflags,
- lcnamep, (u_short)0, (u_short)0);
+ lcnamep, (u_short)0, (u_short)0, (int)0);
}
}
osi_FreeSmallSpace(tbuffer);
#endif /* !AFS_SUN5_ENV */
if (!code)
AFS_COPYOUT ((caddr_t)&mask, (caddr_t)parm3, sizeof(afs_int32), code);
- } else
+ }
+#ifdef AFS_AFSDB_ENV
+ else if (parm == AFSOP_AFSDB_HANDLER) {
+ int sizeArg = (int)parm4;
+ int kmsgLen = sizeArg & 0xffff;
+ int cellLen = (sizeArg & 0xffff0000) >> 16;
+ afs_int32 *kmsg = afs_osi_Alloc(kmsgLen);
+ char *cellname = afs_osi_Alloc(cellLen);
+ AFS_COPYIN((afs_int32 *)parm3, kmsg, kmsgLen, code);
+ if (!code) code = afs_AfsdbHandler(cellname, cellLen, kmsg);
+ if (!code) AFS_COPYOUT(cellname, (char *)parm2, cellLen, code);
+ afs_osi_Free(kmsg, kmsgLen);
+ afs_osi_Free(cellname, cellLen);
+ }
+#endif
+ else
code = EINVAL;
out:
afs_rwlock_t afs_xcell; /* allocation lock for cells */
struct afs_q CellLRU;
afs_int32 afs_cellindex=0;
+afs_uint32 afs_nextCellNum = 0x100;
/* Local variables. */
struct cell *afs_rootcell = 0;
-struct cell *afs_GetCellByName(acellName, locktype)
+static char afs_AfsdbHandlerWait;
+static char afs_AfsdbLookupWait;
+
+char afs_AfsdbHandlerPresent = 0;
+char afs_AfsdbHandlerInuse = 0;
+
+char *afs_AfsdbHandler_CellName;
+afs_int32 *afs_AfsdbHandler_CellHosts;
+int *afs_AfsdbHandler_Timeout;
+
+char afs_AfsdbHandler_ReqPending;
+char afs_AfsdbHandler_Completed;
+
+
+struct cell *afs_GetCellByName_int();
+
+int afs_strcasecmp(s1, s2)
+ register char *s1, *s2;
+{
+ while (*s1 && *s2) {
+ register char c1, c2;
+
+ c1 = *s1++;
+ c2 = *s2++;
+ if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
+ if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
+ if (c1 != c2)
+ return c1-c2;
+ }
+
+ return *s1 - *s2;
+}
+
+
+#ifdef AFS_AFSDB_ENV
+int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
+ char *acellName;
+ int acellNameLen;
+ afs_int32 *kernelMsg;
+{
+ /* afs_syscall_call() has already grabbed the global lock */
+
+ afs_AfsdbHandlerPresent = 1;
+
+ if (afs_AfsdbHandler_ReqPending) {
+ int i, hostCount;
+
+ hostCount = kernelMsg[0];
+ *afs_AfsdbHandler_Timeout = kernelMsg[1];
+ if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
+
+ for (i=0; i<MAXCELLHOSTS; i++) {
+ if (i >= hostCount)
+ afs_AfsdbHandler_CellHosts[i] = 0;
+ else
+ afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
+ }
+
+ /* Request completed, wake up the relevant thread */
+ afs_AfsdbHandler_ReqPending = 0;
+ afs_AfsdbHandler_Completed = 1;
+ afs_osi_Wakeup(&afs_AfsdbLookupWait);
+ }
+
+ /* Wait for a request */
+ while (afs_AfsdbHandler_ReqPending == 0)
+ afs_osi_Sleep(&afs_AfsdbHandlerWait);
+
+ /* Copy the requested cell name into the request buffer */
+ strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
+
+ /* Return the lookup request to userspace */
+ return 0;
+}
+#endif
+
+
+int afs_GetCellHostsFromDns(acellName, acellHosts, timeout)
+ char *acellName;
+ afs_int32 *acellHosts;
+ int *timeout;
+{
+#ifdef AFS_AFSDB_ENV
+ char grab_glock = 0;
+
+ if (!afs_AfsdbHandlerPresent) return ENOENT;
+
+ if (!ISAFS_GLOCK()) {
+ grab_glock = 1;
+ AFS_GLOCK();
+ }
+
+ /* Wait until the AFSDB handler is available, and grab it */
+ while (afs_AfsdbHandlerInuse)
+ afs_osi_Sleep(&afs_AfsdbLookupWait);
+ afs_AfsdbHandlerInuse = 1;
+
+ /* Set up parameters for the handler */
+ afs_AfsdbHandler_CellName = acellName;
+ afs_AfsdbHandler_CellHosts = acellHosts;
+ afs_AfsdbHandler_Timeout = timeout;
+
+ /* Wake up the AFSDB handler */
+ afs_AfsdbHandler_Completed = 0;
+ afs_AfsdbHandler_ReqPending = 1;
+ afs_osi_Wakeup(&afs_AfsdbHandlerWait);
+
+ /* Wait for the handler to get back to us with the reply */
+ while (!afs_AfsdbHandler_Completed)
+ afs_osi_Sleep(&afs_AfsdbLookupWait);
+
+ /* Release the AFSDB handler and wake up others waiting for it */
+ afs_AfsdbHandlerInuse = 0;
+ afs_osi_Wakeup(&afs_AfsdbLookupWait);
+
+ if (grab_glock) AFS_GUNLOCK();
+
+ if (*acellHosts) return 0;
+ return ENOENT;
+#else
+ return ENOENT;
+#endif
+}
+
+
+void afs_RefreshCell(tc)
+ register struct cell *tc;
+{
+ afs_int32 acellHosts[MAXCELLHOSTS];
+ int timeout;
+
+ /* Don't need to do anything if no timeout or it's not expired */
+ if (!tc->timeout || tc->timeout > osi_Time()) return;
+
+ if (!afs_GetCellHostsFromDns(tc->cellName, acellHosts, &timeout)) {
+ afs_NewCell(tc->cellName, acellHosts, tc->states,
+ tc->lcellp ? tc->lcellp->cellName : (char *) 0,
+ tc->fsport, tc->vlport, timeout);
+ }
+
+ /* In case of a DNS failure, keep old cell data.. */
+ return;
+}
+
+
+struct cell *afs_GetCellByName_Dns(acellName, locktype)
+ register char *acellName;
+ afs_int32 locktype;
+{
+ afs_int32 acellHosts[MAXCELLHOSTS];
+ int timeout;
+
+ if (afs_GetCellHostsFromDns(acellName, acellHosts, &timeout))
+ return (struct cell *) 0;
+ if (afs_NewCell(acellName, acellHosts, CNoSUID, (char *) 0, 0, 0, timeout))
+ return (struct cell *) 0;
+
+ return afs_GetCellByName_int(acellName, locktype, 0);
+}
+
+
+struct cell *afs_GetCellByName_int(acellName, locktype, trydns)
register char *acellName;
afs_int32 locktype;
+ char trydns;
{
register struct cell *tc;
register struct afs_q *cq, *tq;
ObtainWriteLock(&afs_xcell,100);
for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
tc = QTOC(cq); tq = QNext(cq);
- if (!strcmp(tc->cellName, acellName)) {
+ if (!afs_strcasecmp(tc->cellName, acellName)) {
QRemove(&tc->lruq);
QAdd(&CellLRU, &tc->lruq);
ReleaseWriteLock(&afs_xcell);
+ afs_RefreshCell(tc);
return tc;
}
}
ReleaseWriteLock(&afs_xcell);
- return (struct cell *) 0;
+ return trydns ? afs_GetCellByName_Dns(acellName, locktype)
+ : (struct cell *) 0;
+
+} /*afs_GetCellByName_int*/
+
+
+struct cell *afs_GetCellByName(acellName, locktype)
+ register char *acellName;
+ afs_int32 locktype;
+{
+ return afs_GetCellByName_int(acellName, locktype, 1);
} /*afs_GetCellByName*/
QRemove(&tc->lruq);
QAdd(&CellLRU, &tc->lruq);
ReleaseWriteLock(&afs_xcell);
+ afs_RefreshCell(tc);
return tc;
}
}
QRemove(&tc->lruq);
QAdd(&CellLRU, &tc->lruq);
ReleaseWriteLock(&afs_xcell);
+ afs_RefreshCell(tc);
return tc;
}
}
} /*afs_GetCellByIndex*/
-afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport)
+afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout)
int aflags;
char *acellName;
register afs_int32 *acellHosts;
char *linkedcname;
u_short fsport, vlport;
+ int timeout;
{
register struct cell *tc, *tcl=0;
register afs_int32 i, newc=0, code=0;
/* Find the cell and mark its servers as not down but gone */
for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
tc = QTOC(cq); tq = QNext(cq);
- if (strcmp(tc->cellName, acellName) == 0) {
+ if (afs_strcasecmp(tc->cellName, acellName) == 0) {
/* we don't want to keep pinging old vlservers which were down,
* since they don't matter any more. It's easier to do this than
* to remove the server from its various hash tables. */
afs_rootcell = tc;
afs_rootCellIndex = tc->cellIndex;
} else {
- tc->cell = *acellHosts; /* won't be reused by another cell */
+ tc->cell = afs_nextCellNum++;
}
tc->states = 0;
tc->lcellp = (struct cell *)0;
}
for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
tcl = QTOC(cq); tq = QNext(cq);
- if (!strcmp(tcl->cellName, linkedcname)) {
+ if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
break;
}
tcl = 0;
tcl->lcellp = tc;
}
tc->states |= aflags;
+ tc->timeout = timeout;
bzero((char *)tc->cellHosts, sizeof(tc->cellHosts));
for (i=0; i<MAXCELLHOSTS; i++) {
extern afs_rwlock_t afs_xcell;
extern struct afs_q CellLRU;
extern afs_int32 afs_cellindex;
+extern afs_int32 afs_nextCellNum;
/* afs_conn.c */
extern afs_rwlock_t afs_xconn;
afs_volCounter = 1;
afs_waitForever = afs_waitForeverCount = 0;
afs_cellindex = 0;
+ afs_nextCellNum = 0x100;
afs_FVIndex = -1;
afs_server = (struct rx_service *)0;
RWLOCK_INIT(&afs_xconn, "afs_xconn");
}
linkedstate |= CNoSUID; /* setuid is disabled by default for fs newcell */
- code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport);
+ code = afs_NewCell(newcell, cellHosts, linkedstate, linkedcell, fsport, vlport, (int)0);
return code;
}
static int preallocs = 400; /* Def # of allocated memory blocks */
static int enable_peer_stats = 0; /* enable rx stats */
static int enable_process_stats = 0; /* enable rx stats */
+#ifdef AFS_AFSDB_ENV
+static int enable_afsdb = 0; /* enable AFSDB support */
+#endif
#ifdef notdef
static int inodes = 60; /* VERY conservative, but has to be */
#endif
return 0;
}
+#ifdef AFS_AFSDB_ENV
+static AfsdbLookupHandler()
+{
+ afs_int32 kernelMsg[64];
+ char acellName[128];
+ afs_int32 code;
+ struct afsconf_cell acellInfo;
+ int i;
+
+ while (1) {
+ /* On some platforms you only get 4 args to an AFS call */
+ int sizeArg = ((sizeof acellName) << 16) | (sizeof kernelMsg);
+ code = call_syscall(AFSOP_AFSDB_HANDLER, acellName, kernelMsg, sizeArg);
+ if (code) { /* Something is wrong? */
+ sleep(1);
+ continue;
+ }
+
+ code = afsconf_GetAfsdbInfo(acellName, 0, &acellInfo);
+ if (code) {
+ kernelMsg[0] = 0;
+ kernelMsg[1] = 0;
+ } else {
+ kernelMsg[0] = acellInfo.numServers;
+ if (acellInfo.timeout)
+ kernelMsg[1] = acellInfo.timeout - time(0);
+ else
+ kernelMsg[1] = 0;
+ for (i=0; i<acellInfo.numServers; i++)
+ kernelMsg[i+2] = acellInfo.hostAddr[i].sin_addr.s_addr;
+ }
+ }
+}
+#endif
+
#ifdef mac2
#include <sys/ioctl.h>
#endif /* mac2 */
/* -mem_alloc_sleep */
cacheFlags |= AFSCALL_INIT_MEMCACHE_SLEEP;
}
+ if (as->parms[24].items) {
+ /* -afsdb */
+#ifdef AFS_AFSDB_ENV
+ enable_afsdb = 1;
+#else
+ printf("afsd: No AFSDB support; ignoring -afsdb");
+#endif
+ }
/*
* Pull out all the configuration info for the workstation's AFS cache and
}
#endif
+#ifdef AFS_AFSDB_ENV
+ if (enable_afsdb) {
+ if (afsd_verbose)
+ printf("%s: Forking AFSDB lookup handler.\n", rn);
+ code = fork();
+ if (code == 0) {
+ AfsdbLookupHandler();
+ exit(1);
+ }
+ }
+#endif
+
/* Initialize AFS daemon threads. */
if (afsd_verbose)
printf("%s: Forking AFS daemon.\n", rn);
}
/*
- * If the root volume has been explicitly set, tell the kernel.
- */
+ * If the root volume has been explicitly set, tell the kernel.
+ */
if (rootVolSet) {
if (afsd_verbose)
printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics by peer");
cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics for this process");
cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE), "Allow sleeps when allocating memory cache");
+ cmd_AddParm(ts, "-afsdb", CMD_FLAG, (CMD_OPTIONAL
+#ifndef AFS_AFSDB_ENV
+ | CMD_HIDE
+#endif
+ ), "Enable AFSDB support");
return (cmd_Dispatch(argc, argv));
}
#include <netdb.h>
#include <sys/file.h>
#include <sys/time.h>
-#endif
+#ifdef AFS_AFSDB_ENV
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif /* AFS_AFSDB_ENV */
+#endif /* AFS_NT40_ENV */
#include <errno.h>
#include <ctype.h>
#include <time.h>
return code;
}
+#ifdef AFS_AFSDB_ENV
+afsconf_GetAfsdbInfo(acellName, aservice, acellInfo)
+ char *acellName;
+ char *aservice;
+ struct afsconf_cell *acellInfo;
+{
+ afs_int32 code;
+ int tservice, len, i;
+ unsigned char answer[1024];
+ unsigned char *p;
+ char host[256];
+ int server_num = 0;
+ int minttl = 0;
+
+ /* The resolver isn't always MT-safe.. Perhaps this ought to be
+ * replaced with a more fine-grained lock just for the resolver
+ * operations.
+ */
+ LOCK_GLOBAL_MUTEX
+ len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
+ UNLOCK_GLOBAL_MUTEX
+
+ if (len < 0)
+ return AFSCONF_NOTFOUND;
+
+ p = answer + sizeof(HEADER); /* Skip header */
+ code = dn_expand(answer, answer + len, p, host, sizeof(host));
+ if (code < 0)
+ return AFSCONF_NOTFOUND;
+ strncpy(acellInfo->name, host, sizeof(acellInfo->name));
+
+ p += code + QFIXEDSZ; /* Skip name */
+
+ while (p < answer + len) {
+ int type, ttl, size;
+
+ code = dn_expand(answer, answer + len, p, host, sizeof(host));
+ if (code < 0)
+ return AFSCONF_NOTFOUND;
+
+ p += code; /* Skip the name */
+ type = (p[0] << 8) | p[1];
+ p += 4; /* Skip type and class */
+ ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ p += 4; /* Skip the TTL */
+ size = (p[0] << 8) | p[1];
+ p += 2; /* Skip the size */
+
+ if (type == T_AFSDB) {
+ struct hostent *he;
+
+ code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
+ if (code < 0)
+ return AFSCONF_NOTFOUND;
+
+ /* Do we want to get TTL data for the A record as well? */
+ he = gethostbyname(host);
+ if (he && server_num < MAXHOSTSPERCELL) {
+ afs_int32 ipaddr;
+ memcpy(&ipaddr, he->h_addr, he->h_length);
+ acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
+ strncpy(acellInfo->hostName[server_num], host,
+ sizeof(acellInfo->hostName[server_num]));
+ server_num++;
+
+ if (!minttl || ttl < minttl) minttl = ttl;
+ }
+ }
+
+ p += size;
+ }
+
+ if (server_num == 0) /* No AFSDB records */
+ return AFSCONF_NOTFOUND;
+ acellInfo->numServers = server_num;
+
+ if (aservice) {
+ tservice = afsconf_FindService(aservice);
+ if (tservice < 0)
+ return AFSCONF_NOTFOUND; /* service not found */
+ for (i=0; i<acellInfo->numServers; i++) {
+ acellInfo->hostAddr[i].sin_port = tservice;
+ }
+ }
+
+ acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
+
+ return 0;
+}
+#endif /* AFS_AFSDB_ENV */
+
afsconf_GetCellInfo(adir, acellName, aservice, acellInfo)
struct afsconf_dir *adir;
char *aservice;
acellInfo->hostAddr[i].sin_port = tservice;
}
}
+ acellInfo->timeout = 0;
UNLOCK_GLOBAL_MUTEX
return 0;
}
else {
UNLOCK_GLOBAL_MUTEX
+#ifdef AFS_AFSDB_ENV
+ return afsconf_GetAfsdbInfo(acellName, aservice, acellInfo);
+#else
return AFSCONF_NOTFOUND;
+#endif /* AFS_AFSDB_ENV */
}
}
struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; /*IP addresses for cell's servers*/
char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; /*Names for cell's servers*/
char *linkedCell; /* Linked cell name, if any */
+ int timeout; /* Data timeout, if non-zero */
};
struct afsconf_entry {
#define AFSOP_GETIFADDRS 21 /* get machine's ethernet interfaces */
#define AFSOP_ADDCELL2 29 /* 2nd add cell protocol interface */
+#define AFSOP_AFSDB_HANDLER 30 /* userspace AFSDB lookup handler */
/* The range 20-30 is reserved for AFS system offsets in the afs_syscall */
#define AFSCALL_PIOCTL 20