darwin-updates-20020821
[openafs.git] / src / afs / afs_cell.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  */
13 #include <afsconfig.h>
14 #include "../afs/param.h"
15
16 RCSID("$Header$");
17
18 #include "../afs/stds.h"
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
20
21 #if !defined(UKERNEL)
22 #include <net/if.h>
23 #include <netinet/in.h>
24
25 #ifdef AFS_SGI62_ENV
26 #include "../h/hashing.h"
27 #endif
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) */
32
33 #include "../afs/afsincludes.h" /* Afs-based standard headers */
34 #include "../afs/afs_stats.h"   /* afs statistics */
35
36 #if     defined(AFS_SUN56_ENV)
37 #include <inet/led.h>
38 #include <inet/common.h>
39 #if     defined(AFS_SUN58_ENV)
40 #include <netinet/ip6.h>
41 #endif
42 #include <inet/ip.h>
43 #endif
44
45 /* Exported variables */
46 afs_rwlock_t afs_xcell;                 /* allocation lock for cells */
47 struct afs_q CellLRU;
48 afs_int32 afs_cellindex=0;
49 afs_int32 afs_realcellindex=0;
50 afs_uint32 afs_nextCellNum = 0x100;
51
52 /* Local variables. */
53 struct cell *afs_rootcell = 0;
54
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;
59
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;
67
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;
74
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;
79
80 int afs_strcasecmp(register char *s1, register char *s2)
81 {
82     while (*s1 && *s2) {
83         register char c1, c2;
84
85         c1 = *s1++;
86         c2 = *s2++;
87         if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
88         if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
89         if (c1 != c2)
90             return c1-c2;
91     }
92
93     return *s1 - *s2;
94 }
95
96
97 #ifdef AFS_AFSDB_ENV
98 void afs_StopAfsdb(void)
99 {
100     if (afs_AfsdbHandlerPresent) {
101         afs_osi_Wakeup(&afs_AfsdbHandlerWait);
102     } else {
103         afs_AfsdbHandlerShutdown = 1;
104         afs_termState = AFSOP_STOP_RXEVENT;
105     }
106 }
107
108 int afs_AfsdbHandler(char *acellName, int acellNameLen, afs_int32 *kernelMsg)
109 {
110     /* afs_syscall_call() has already grabbed the global lock */
111
112     if (afs_AfsdbHandlerShutdown) return -2;
113     afs_AfsdbHandlerPresent = 1;
114
115     if (afs_AfsdbHandler_ReqPending) {
116         int i, hostCount;
117
118         hostCount = kernelMsg[0];
119         *afs_AfsdbHandler_Timeout = kernelMsg[1];
120         if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
121
122         *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
123         strcpy(*afs_AfsdbHandler_RealName, acellName);
124
125         for (i=0; i<MAXCELLHOSTS; i++) {
126             if (i >= hostCount)
127                 afs_AfsdbHandler_CellHosts[i] = 0;
128             else
129                 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
130         }
131
132         /* Request completed, wake up the relevant thread */
133         afs_AfsdbHandler_ReqPending = 0;
134         afs_AfsdbHandler_Completed = 1;
135         afs_osi_Wakeup(&afs_AfsdbLookupWait);
136     }
137
138     /* Wait for a request */
139     while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
140         afs_osi_Sleep(&afs_AfsdbHandlerWait);
141
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);
148
149         afs_termState = AFSOP_STOP_RXEVENT;
150         afs_osi_Wakeup(&afs_termState);
151         return -2;
152     }
153
154     /* Copy the requested cell name into the request buffer */
155     strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
156
157     /* Return the lookup request to userspace */    
158     return 0;
159 }
160 #endif
161
162
163 int afs_GetCellHostsFromDns(char *acellName, afs_int32 *acellHosts, 
164         int *timeout, char **realName)
165 {
166 #ifdef AFS_AFSDB_ENV
167     char grab_glock = 0;
168
169     if (!afs_AfsdbHandlerPresent) return ENOENT;
170
171     /* Initialize host list to empty in case the handler is gone */
172     *acellHosts = 0;
173
174     if (!ISAFS_GLOCK()) {
175         grab_glock = 1;
176         AFS_GLOCK();
177     }
178
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;
183
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;
189
190     /* Wake up the AFSDB handler */
191     afs_AfsdbHandler_Completed = 0;
192     afs_AfsdbHandler_ReqPending = 1;
193     afs_osi_Wakeup(&afs_AfsdbHandlerWait);
194
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);
198
199     /* Release the AFSDB handler and wake up others waiting for it */
200     afs_AfsdbHandlerInuse = 0;
201     afs_osi_Wakeup(&afs_AfsdbLookupWait);
202
203     if (grab_glock) AFS_GUNLOCK();
204
205     if (*acellHosts) return 0;
206     return ENOENT;
207 #else
208     return ENOENT;
209 #endif
210 }
211
212
213 void afs_RefreshCell(register struct cell *ac)
214 {
215     afs_int32 cellHosts[MAXCELLHOSTS];
216     char *realName = NULL;
217     struct cell *tc;
218     int timeout;
219
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 */
223             return;
224
225     if (afs_GetCellHostsFromDns(ac->cellName, cellHosts, &timeout, &realName))
226         /* In case of lookup failure, keep old data */
227         goto done;
228
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);
231
232     /* If this is an alias, update the alias entry too */
233     if (afs_strcasecmp(ac->cellName, realName)) {
234         /*
235          * Look up the entry we just updated, to compensate for
236          * uppercase-vs-lowercase lossage with DNS.
237          */
238         tc = afs_FindCellByName(realName, READ_LOCK);
239
240         if (tc) {
241             afs_NewCell(ac->cellName, 0, CAlias, NULL, 0, 0,
242                         timeout, tc->cellName);
243             afs_PutCell(tc, READ_LOCK);
244         }
245     }
246
247 done:
248     if (realName)
249         afs_osi_Free(realName, strlen(realName) + 1);
250 }
251
252
253 struct cell *afs_GetCellByName_Dns(register char *acellName, afs_int32 locktype)
254 {
255     afs_int32 cellHosts[MAXCELLHOSTS];
256     char *realName = NULL;
257     struct cell *tc;
258     int timeout;
259
260     if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
261         goto bad;
262     if (afs_NewCell(realName, cellHosts, CNoSUID, NULL, 0, 0,
263                     timeout, NULL))
264         goto bad;
265
266     /* If this is an alias, create an entry for it too */
267     if (afs_strcasecmp(acellName, realName)) {
268         /*
269          * Look up the entry we just updated, to compensate for
270          * uppercase-vs-lowercase lossage with DNS.
271          */
272         tc = afs_FindCellByName(realName, READ_LOCK);
273         if (!tc)
274             goto bad;
275
276         if (afs_NewCell(acellName, 0, CAlias, NULL, 0, 0,
277                         timeout, tc->cellName)) {
278             afs_PutCell(tc, READ_LOCK);
279             goto bad;
280         }
281
282         afs_PutCell(tc, READ_LOCK);
283     }
284
285     if (realName)
286         afs_osi_Free(realName, strlen(realName) + 1);
287     return afs_FindCellByName(acellName, locktype);
288
289 bad:
290     if (realName)
291         afs_osi_Free(realName, strlen(realName) + 1);
292     return NULL;
293 }
294
295
296 struct cell *afs_FindCellByName(register char *acellName, afs_int32 locktype)
297 {
298     register struct cell *tc;
299     register struct afs_q *cq, *tq;
300     int didAlias = 0;
301
302     AFS_STATCNT(afs_GetCellByName);
303 retry:
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)) {
308             QRemove(&tc->lruq);
309             QAdd(&CellLRU, &tc->lruq);
310             ReleaseWriteLock(&afs_xcell);
311             afs_RefreshCell(tc);
312             if ((tc->states & CAlias) && (didAlias == 0)) {
313                 acellName = tc->realName;
314                 if (!acellName) return NULL;
315                 didAlias = 1;
316                 goto retry;
317             }
318             return tc;
319         }
320     }
321
322     ReleaseWriteLock(&afs_xcell);
323     return NULL;
324 }
325
326 struct cell *afs_GetCellByName(register char *acellName, afs_int32 locktype)
327 {
328     struct cell *tc;
329
330     tc = afs_FindCellByName(acellName, locktype);
331     if (!tc)
332         tc = afs_GetCellByName_Dns(acellName, locktype);
333   
334     return tc;
335 }
336
337 static struct cell *afs_GetCellInternal(register afs_int32 acell, 
338         afs_int32 locktype, int holdxcell)
339 {
340     register struct cell *tc;
341     register struct afs_q *cq, *tq;
342
343     AFS_STATCNT(afs_GetCell);
344     if (acell == 1 && afs_rootcell) return afs_rootcell;
345     if (holdxcell)
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) {
350             QRemove(&tc->lruq);
351             QAdd(&CellLRU, &tc->lruq);
352             if (holdxcell)
353                 ReleaseWriteLock(&afs_xcell);
354             afs_RefreshCell(tc);
355             return tc;
356         }
357     }
358     if (holdxcell)
359         ReleaseWriteLock(&afs_xcell);
360     return NULL;
361
362 }
363
364 struct cell *afs_GetCell(register afs_int32 acell, afs_int32 locktype)
365 {
366     return afs_GetCellInternal(acell, locktype, 1);
367 }
368
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)
371 {
372     return afs_GetCellInternal(acell, locktype, 0);
373 }
374
375 struct cell *afs_GetCellByIndex(register afs_int32 cellindex, 
376         afs_int32 locktype, afs_int32 refresh)
377 {
378     register struct cell *tc;
379     register struct afs_q *cq, *tq;
380
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) {
386             QRemove(&tc->lruq);
387             QAdd(&CellLRU, &tc->lruq);
388             ReleaseWriteLock(&afs_xcell);
389             if (refresh) afs_RefreshCell(tc);
390             return tc;
391         }
392     }
393     ReleaseWriteLock(&afs_xcell);
394     return NULL;
395
396 }
397
398
399 struct cell *afs_GetRealCellByIndex(register afs_int32 cellindex, afs_int32 locktype, afs_int32 refresh)
400 {
401     register struct cell *tc;
402     register struct afs_q *cq, *tq;
403
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) {
409             QRemove(&tc->lruq);
410             QAdd(&CellLRU, &tc->lruq);
411             ReleaseWriteLock(&afs_xcell);
412             if (refresh) afs_RefreshCell(tc);
413             return tc;
414         }
415     }
416     ReleaseWriteLock(&afs_xcell);
417     return NULL;
418 } /*afs_GetRealCellByIndex*/
419
420
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)
423 {
424     register struct cell *tc, *tcl=0;
425     register afs_int32 i, newc=0, code=0;
426     register struct afs_q *cq, *tq;
427
428     AFS_STATCNT(afs_NewCell);
429
430     ObtainWriteLock(&afs_xcell,103);
431
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.
441              */
442             if (timeout && !tc->timeout && tc->cellHosts[0]) {
443                 ReleaseWriteLock(&afs_xcell);
444                 return 0;
445             }
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;
453             }
454             break;
455         }
456     }
457
458     if (cq != &CellLRU) {
459         aflags &= ~CNoSUID;
460     }
461     else {
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 */
471             afs_rootcell = tc;
472             afs_rootCellIndex = tc->cellIndex;
473         } else {
474             tc->cell = afs_nextCellNum++;
475         }
476         tc->states = 0;
477         tc->lcellp = NULL;
478         tc->fsport = (fsport ? fsport : AFS_FSPORT);
479         tc->vlport = (vlport ? vlport : AFS_VLPORT);
480         afs_stats_cmperf.numCellsVisible++;
481         newc++;
482         if (!(aflags & CAlias)) {
483             tc->realcellIndex = afs_realcellindex++;
484         } else {
485             tc->realcellIndex = -1;
486         }
487     }
488
489     if (aflags & CLinkedCell) {
490         if (!linkedcname) {
491             code = EINVAL;
492             goto bad;
493         }
494         for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
495             tcl = QTOC(cq); tq = QNext(cq);
496             if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
497                 break;
498             }
499             tcl = 0;
500         }
501         if (!tcl) {
502             code = ENOENT;
503             goto bad;
504         }
505         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
506             tcl->lcellp->lcellp = NULL;
507             tcl->lcellp->states &= ~CLinkedCell;
508         }
509         tc->lcellp = tcl;
510         tcl->lcellp = tc;
511     }
512     tc->states |= aflags;
513     tc->timeout = timeout;
514
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++;
519     }
520  
521     memset((char *)tc->cellHosts, 0, sizeof(tc->cellHosts));
522     if (aflags & CAlias) {
523         if (!aliasFor) {
524             code = EINVAL;
525             goto bad;
526         }
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);
530         goto done;
531     }
532
533     for (i=0; i<MAXCELLHOSTS; i++) {
534         struct server *ts;
535         afs_uint32 temp = acellHosts[i];
536         if (!temp) break;
537         ts = afs_GetServer(&temp, 1, 0, tc->vlport, WRITE_LOCK, (afsUUID *)0, 0);
538         ts->cell = tc;
539         ts->flags &= ~SRVR_ISGONE;
540         tc->cellHosts[i] = ts;
541         afs_PutServer(ts, WRITE_LOCK);
542     }
543     afs_SortServers(tc->cellHosts, MAXCELLHOSTS);       /* randomize servers */
544 done:
545     ReleaseWriteLock(&afs_xcell);
546     return 0;
547 bad:
548     if (newc) {
549         QRemove(&tc->lruq);
550         afs_osi_Free(tc->cellName, strlen(tc->cellName)+1);
551         afs_osi_Free((char *)tc, sizeof(struct cell));
552     }
553     ReleaseWriteLock(&afs_xcell);
554     return code;
555 }
556
557 void afs_RemoveCellEntry(struct server *srvp)
558 {
559   struct cell *tc;
560   afs_int32 j, k;
561
562   tc = srvp->cell;
563   if (!tc) return;
564
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];
571      }
572   }
573   if (k == 0) {
574      /* What do we do if we remove the last one? */
575   }
576   for (; k<MAXCELLHOSTS; k++) {
577      tc->cellHosts[k] = 0;
578   }
579   ReleaseWriteLock(&afs_xcell);
580 }
581