Support empty CellServDB entries like arla; this is useful to
[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)
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_uint32 afs_nextCellNum = 0x100;
50
51
52 /* Local variables. */
53 struct cell *afs_rootcell = 0;
54
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;
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
81 int afs_strcasecmp(s1, s2)
82     register char *s1, *s2;
83 {
84     while (*s1 && *s2) {
85         register char c1, c2;
86
87         c1 = *s1++;
88         c2 = *s2++;
89         if (c1 >= 'A' && c1 <= 'Z') c1 += 0x20;
90         if (c2 >= 'A' && c2 <= 'Z') c2 += 0x20;
91         if (c1 != c2)
92             return c1-c2;
93     }
94
95     return *s1 - *s2;
96 }
97
98
99 #ifdef AFS_AFSDB_ENV
100 void afs_StopAfsdb()
101 {
102     if (afs_AfsdbHandlerPresent) {
103         afs_osi_Wakeup(&afs_AfsdbHandlerWait);
104     } else {
105         afs_AfsdbHandlerShutdown = 1;
106         afs_termState = AFSOP_STOP_RXEVENT;
107     }
108 }
109
110 int afs_AfsdbHandler(acellName, acellNameLen, kernelMsg)
111     char *acellName;
112     int acellNameLen;
113     afs_int32 *kernelMsg;
114 {
115     /* afs_syscall_call() has already grabbed the global lock */
116
117     if (afs_AfsdbHandlerShutdown) return -2;
118     afs_AfsdbHandlerPresent = 1;
119
120     if (afs_AfsdbHandler_ReqPending) {
121         int i, hostCount;
122
123         hostCount = kernelMsg[0];
124         *afs_AfsdbHandler_Timeout = kernelMsg[1];
125         if (*afs_AfsdbHandler_Timeout) *afs_AfsdbHandler_Timeout += osi_Time();
126
127         *afs_AfsdbHandler_RealName = afs_osi_Alloc(strlen(acellName) + 1);
128         strcpy(*afs_AfsdbHandler_RealName, acellName);
129
130         for (i=0; i<MAXCELLHOSTS; i++) {
131             if (i >= hostCount)
132                 afs_AfsdbHandler_CellHosts[i] = 0;
133             else
134                 afs_AfsdbHandler_CellHosts[i] = kernelMsg[2+i];
135         }
136
137         /* Request completed, wake up the relevant thread */
138         afs_AfsdbHandler_ReqPending = 0;
139         afs_AfsdbHandler_Completed = 1;
140         afs_osi_Wakeup(&afs_AfsdbLookupWait);
141     }
142
143     /* Wait for a request */
144     while (afs_AfsdbHandler_ReqPending == 0 && afs_termState != AFSOP_STOP_AFSDB)
145         afs_osi_Sleep(&afs_AfsdbHandlerWait);
146
147     /* Check if we're shutting down */
148     if (afs_termState == AFSOP_STOP_AFSDB) {
149         /* Inform anyone waiting for us that we're going away */
150         afs_AfsdbHandlerShutdown = 1;
151         afs_AfsdbHandlerPresent = 0;
152         afs_osi_Wakeup(&afs_AfsdbLookupWait);
153
154         afs_termState = AFSOP_STOP_RXEVENT;
155         afs_osi_Wakeup(&afs_termState);
156         return -2;
157     }
158
159     /* Copy the requested cell name into the request buffer */
160     strncpy(acellName, afs_AfsdbHandler_CellName, acellNameLen);
161
162     /* Return the lookup request to userspace */    
163     return 0;
164 }
165 #endif
166
167
168 int afs_GetCellHostsFromDns(acellName, acellHosts, timeout, realName)
169     char *acellName;
170     afs_int32 *acellHosts;
171     int *timeout;
172     char **realName;
173 {
174 #ifdef AFS_AFSDB_ENV
175     char grab_glock = 0;
176
177     if (!afs_AfsdbHandlerPresent) return ENOENT;
178
179     /* Initialize host list to empty in case the handler is gone */
180     *acellHosts = 0;
181
182     if (!ISAFS_GLOCK()) {
183         grab_glock = 1;
184         AFS_GLOCK();
185     }
186
187     /* Wait until the AFSDB handler is available, and grab it */
188     while (afs_AfsdbHandlerInuse)
189         afs_osi_Sleep(&afs_AfsdbLookupWait);
190     afs_AfsdbHandlerInuse = 1;
191
192     /* Set up parameters for the handler */
193     afs_AfsdbHandler_CellName = acellName;
194     afs_AfsdbHandler_CellHosts = acellHosts;
195     afs_AfsdbHandler_Timeout = timeout;
196     afs_AfsdbHandler_RealName = realName;
197
198     /* Wake up the AFSDB handler */
199     afs_AfsdbHandler_Completed = 0;
200     afs_AfsdbHandler_ReqPending = 1;
201     afs_osi_Wakeup(&afs_AfsdbHandlerWait);
202
203     /* Wait for the handler to get back to us with the reply */
204     while (afs_AfsdbHandlerPresent && !afs_AfsdbHandler_Completed)
205         afs_osi_Sleep(&afs_AfsdbLookupWait);
206
207     /* Release the AFSDB handler and wake up others waiting for it */
208     afs_AfsdbHandlerInuse = 0;
209     afs_osi_Wakeup(&afs_AfsdbLookupWait);
210
211     if (grab_glock) AFS_GUNLOCK();
212
213     if (*acellHosts) return 0;
214     return ENOENT;
215 #else
216     return ENOENT;
217 #endif
218 }
219
220
221 void afs_RefreshCell(ac)
222     register struct cell *ac;
223 {
224     afs_int32 cellHosts[MAXCELLHOSTS];
225     char *realName = NULL;
226     struct cell *tc;
227     int timeout;
228
229     if (ac->cellHosts[0])       /* If we already have some servers.. */
230         if (!ac->timeout || ac->timeout > osi_Time())
231                                 /* Don't refresh if not expired */
232             return;
233
234     if (afs_GetCellHostsFromDns(ac->cellName, cellHosts, &timeout, &realName))
235         /* In case of lookup failure, keep old data */
236         goto done;
237
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);
240
241     /* If this is an alias, update the alias entry too */
242     if (afs_strcasecmp(ac->cellName, realName)) {
243         /*
244          * Look up the entry we just updated, to compensate for
245          * uppercase-vs-lowercase lossage with DNS.
246          */
247         tc = afs_FindCellByName(realName, READ_LOCK);
248
249         if (tc) {
250             afs_NewCell(ac->cellName, 0, CAlias, (char *) 0, 0, 0,
251                         timeout, tc->cellName);
252             afs_PutCell(tc, READ_LOCK);
253         }
254     }
255
256 done:
257     if (realName)
258         afs_osi_Free(realName, strlen(realName) + 1);
259 }
260
261
262 struct cell *afs_GetCellByName_Dns(acellName, locktype)
263     register char *acellName;
264     afs_int32 locktype;
265 {
266     afs_int32 cellHosts[MAXCELLHOSTS];
267     char *realName = NULL;
268     struct cell *tc;
269     int timeout;
270
271     if (afs_GetCellHostsFromDns(acellName, cellHosts, &timeout, &realName))
272         goto bad;
273     if (afs_NewCell(realName, cellHosts, CNoSUID, (char *) 0, 0, 0,
274                     timeout, (char *) 0))
275         goto bad;
276
277     /* If this is an alias, create an entry for it too */
278     if (afs_strcasecmp(acellName, realName)) {
279         /*
280          * Look up the entry we just updated, to compensate for
281          * uppercase-vs-lowercase lossage with DNS.
282          */
283         tc = afs_FindCellByName(realName, READ_LOCK);
284         if (!tc)
285             goto bad;
286
287         if (afs_NewCell(acellName, 0, CAlias, (char *) 0, 0, 0,
288                         timeout, tc->cellName)) {
289             afs_PutCell(tc, READ_LOCK);
290             goto bad;
291         }
292
293         afs_PutCell(tc, READ_LOCK);
294     }
295
296     if (realName)
297         afs_osi_Free(realName, strlen(realName) + 1);
298     return afs_FindCellByName(acellName, locktype);
299
300 bad:
301     if (realName)
302         afs_osi_Free(realName, strlen(realName) + 1);
303     return (struct cell *) 0;
304 }
305
306
307 struct cell *afs_FindCellByName(acellName, locktype)
308     register char *acellName;
309     afs_int32 locktype;
310 {
311     register struct cell *tc;
312     register struct afs_q *cq, *tq;
313     int didAlias = 0;
314
315     AFS_STATCNT(afs_GetCellByName);
316 retry:
317     ObtainWriteLock(&afs_xcell,100);
318     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
319         tc = QTOC(cq); tq = QNext(cq);
320         if (!afs_strcasecmp(tc->cellName, acellName)) {
321             QRemove(&tc->lruq);
322             QAdd(&CellLRU, &tc->lruq);
323             ReleaseWriteLock(&afs_xcell);
324             afs_RefreshCell(tc);
325             if ((tc->states & CAlias) && (didAlias == 0)) {
326                 acellName = tc->realName;
327                 if (!acellName) return (struct cell *) 0;
328                 didAlias = 1;
329                 goto retry;
330             }
331             return tc;
332         }
333     }
334
335     ReleaseWriteLock(&afs_xcell);
336     return (struct cell *) 0;
337 } /*afs_FindCellByName*/
338
339
340 struct cell *afs_GetCellByName(acellName, locktype)
341     register char *acellName;
342     afs_int32 locktype;
343 {
344     struct cell *tc;
345
346     tc = afs_FindCellByName(acellName, locktype);
347     if (!tc)
348         tc = afs_GetCellByName_Dns(acellName, locktype);
349
350     return tc;
351 } /*afs_GetCellByName*/
352
353 static struct cell *afs_GetCellInternal(acell, locktype, holdxcell)
354     register afs_int32 acell;
355     afs_int32 locktype;
356     int holdxcell;
357 {
358     register struct cell *tc;
359     register struct afs_q *cq, *tq;
360
361     AFS_STATCNT(afs_GetCell);
362     if (acell == 1 && afs_rootcell) return afs_rootcell;
363     if (holdxcell)
364         ObtainWriteLock(&afs_xcell,101);
365     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
366         tc = QTOC(cq); tq = QNext(cq);
367         if (tc->cell == acell) {
368             QRemove(&tc->lruq);
369             QAdd(&CellLRU, &tc->lruq);
370             if (holdxcell)
371                 ReleaseWriteLock(&afs_xcell);
372             afs_RefreshCell(tc);
373             return tc;
374         }
375     }
376     if (holdxcell)
377         ReleaseWriteLock(&afs_xcell);
378     return (struct cell *) 0;
379
380 } /*afs_GetCell*/
381
382 struct cell *afs_GetCell(acell, locktype)
383     register afs_int32 acell;
384     afs_int32 locktype;
385 {
386     return afs_GetCellInternal(acell, locktype, 1);
387 }
388
389 /* This is only to be called if the caller is already holding afs_xcell */
390 struct cell *afs_GetCellNoLock(acell, locktype)
391     register afs_int32 acell;
392     afs_int32 locktype;
393 {
394     return afs_GetCellInternal(acell, locktype, 0);
395 }
396
397 struct cell *afs_GetCellByIndex(cellindex, locktype, refresh)
398     register afs_int32 cellindex;
399     afs_int32 locktype;
400     afs_int32 refresh;
401 {
402     register struct cell *tc;
403     register struct afs_q *cq, *tq;
404
405     AFS_STATCNT(afs_GetCellByIndex);
406     ObtainWriteLock(&afs_xcell,102);
407     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
408         tc = QTOC(cq); tq = QNext(cq);
409         if (tc->cellIndex == cellindex) {
410             QRemove(&tc->lruq);
411             QAdd(&CellLRU, &tc->lruq);
412             ReleaseWriteLock(&afs_xcell);
413             if (refresh) afs_RefreshCell(tc);
414             return tc;
415         }
416     }
417     ReleaseWriteLock(&afs_xcell);
418     return (struct cell *) 0;
419
420 } /*afs_GetCellByIndex*/
421
422
423 afs_int32 afs_NewCell(acellName, acellHosts, aflags, linkedcname, fsport, vlport, timeout, aliasFor)
424     int aflags;
425     char *acellName;
426     register afs_int32 *acellHosts;
427     char *linkedcname;
428     u_short fsport, vlport;
429     int timeout;
430     char *aliasFor;
431 {
432     register struct cell *tc, *tcl=0;
433     register afs_int32 i, newc=0, code=0;
434     register struct afs_q *cq, *tq;
435
436     AFS_STATCNT(afs_NewCell);
437
438     ObtainWriteLock(&afs_xcell,103);
439
440     /* Find the cell and mark its servers as not down but gone */
441     for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
442         tc = QTOC(cq); tq = QNext(cq);
443         if (afs_strcasecmp(tc->cellName, acellName) == 0) {
444             /* If the cell we've found has the correct name but no timeout,
445              * and we're called with a non-zero timeout, bail out:  never
446              * override static configuration entries with AFSDB ones.
447              * One exception: if the original cell entry had no servers,
448              * it must get servers from AFSDB.
449              */
450             if (timeout && !tc->timeout && tc->cellHosts[0]) {
451                 ReleaseWriteLock(&afs_xcell);
452                 return 0;
453             }
454             /* we don't want to keep pinging old vlservers which were down,
455              * since they don't matter any more.  It's easier to do this than
456              * to remove the server from its various hash tables. */
457             for (i=0; i<MAXCELLHOSTS; i++) {
458                 if (!tc->cellHosts[i]) break;
459                 tc->cellHosts[i]->flags &= ~SRVR_ISDOWN;
460                 tc->cellHosts[i]->flags |= SRVR_ISGONE;
461             }
462             break;
463         }
464     }
465
466     if (cq != &CellLRU) {
467         aflags &= ~CNoSUID;
468     }
469     else {
470         tc = (struct cell *) afs_osi_Alloc(sizeof(struct cell));
471         memset((char *)tc, 0, sizeof(*tc));
472         QAdd(&CellLRU, &tc->lruq);                      /* put in lruq */
473         tc->cellName = (char *) afs_osi_Alloc(strlen(acellName)+1);
474         strcpy(tc->cellName, acellName);
475         tc->cellIndex = afs_cellindex++;
476         if (aflags & CPrimary) {
477             extern int afs_rootCellIndex;
478             tc->cell = 1;       /* primary cell is always 1 */
479             afs_rootcell = tc;
480             afs_rootCellIndex = tc->cellIndex;
481         } else {
482             tc->cell = afs_nextCellNum++;
483         }
484         tc->states = 0;
485         tc->lcellp = (struct cell *)0;
486         tc->fsport = (fsport ? fsport : AFS_FSPORT);
487         tc->vlport = (vlport ? vlport : AFS_VLPORT);
488         afs_stats_cmperf.numCellsVisible++;
489         newc++;
490     }
491
492     if (aflags & CLinkedCell) {
493         if (!linkedcname) {
494             code = EINVAL;
495             goto bad;
496         }
497         for (cq = CellLRU.next; cq != &CellLRU; cq = tq) {
498             tcl = QTOC(cq); tq = QNext(cq);
499             if (!afs_strcasecmp(tcl->cellName, linkedcname)) {
500                 break;
501             }
502             tcl = 0;
503         }
504         if (!tcl) {
505             code = ENOENT;
506             goto bad;
507         }
508         if (tcl->lcellp) {      /* XXX Overwriting if one existed before! XXX */
509             tcl->lcellp->lcellp = (struct cell *)0;
510             tcl->lcellp->states &= ~CLinkedCell;
511         }
512         tc->lcellp = tcl;
513         tcl->lcellp = tc;
514     }
515     tc->states |= aflags;
516     tc->timeout = timeout;
517
518     /* Allow converting an alias into a real cell */
519     if (!(aflags & CAlias)) tc->states &= ~CAlias;
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 } /*afs_NewCell*/
557
558 afs_RemoveCellEntry(struct server *srvp)
559 {
560   struct cell *tc;
561   afs_int32 j, k;
562
563   tc = srvp->cell;
564   if (!tc) return;
565
566   /* Remove the server structure from the cell list - if there */
567   ObtainWriteLock(&afs_xcell,200);
568   for (j=k=0; j<MAXCELLHOSTS; j++) {
569      if (!tc->cellHosts[j]) break;
570      if (tc->cellHosts[j] != srvp) {
571         tc->cellHosts[k++] = tc->cellHosts[j];
572      }
573   }
574   if (k == 0) {
575      /* What do we do if we remove the last one? */
576   }
577   for (; k<MAXCELLHOSTS; k++) {
578      tc->cellHosts[k] = 0;
579   }
580   ReleaseWriteLock(&afs_xcell);
581 }
582