no-copy-libafs-builds-20021015
[openafs.git] / src / ubik / ubikclient.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 #include <afsconfig.h>
11 #if defined(UKERNEL)
12 #include "afs/param.h"
13 #else
14 #include <afs/param.h>
15 #endif
16
17 RCSID("$Header$");
18
19 #if defined(UKERNEL)
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22 #include "afs/stds.h"
23 #include "rx/xdr.h"
24 #include "rx/rx.h"
25 #include "afs/lock.h"
26 #include "afs/rxgen_consts.h"
27 #include "ubik.h"
28 #include "afs/pthread_glock.h"
29 #else /* defined(UKERNEL) */
30 #include <afs/stds.h>
31 #include <afs/pthread_glock.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <rx/xdr.h>
35 #include <rx/rx.h>
36 #include <lock.h>
37 #ifdef AFS_NT40_ENV
38 #include <winsock2.h>
39 #else
40 #include <netdb.h>
41 #include <netinet/in.h>
42 #endif
43 #include <afs/rxgen_consts.h>
44 #include "ubik.h"
45 #endif /* defined(UKERNEL) */
46
47
48 afs_int32 ubik_CallIter();
49 short ubik_initializationState; /* initial state is zero */
50
51
52 /*
53  * parse list for clients
54  */
55 int ubik_ParseClientList(
56   int argc,
57   char **argv,
58   afs_int32 *aothers)
59 {
60     register afs_int32 i;
61     register char *tp;
62     register struct hostent *th;
63     afs_int32 temp, counter;
64     int inServer;
65     
66     inServer = 0;       /* haven't seen -servers yet */
67     counter = 0;
68     for(i=1; i<argc; i++) {
69         /* look for -servers argument */
70         tp = argv[i];
71         
72         if (inServer) {
73             if (*tp == '-') break;  /* done */
74             /* otherwise this is a new host name */
75             LOCK_GLOBAL_MUTEX
76             th = gethostbyname(tp);
77             if (!th) {
78                 UNLOCK_GLOBAL_MUTEX
79                 return UBADHOST;
80             }
81             memmove((void *) &temp, (const void *) th->h_addr, sizeof(afs_int32));
82             UNLOCK_GLOBAL_MUTEX
83             if (counter++ >= MAXSERVERS) return UNHOSTS;
84             *aothers++ = temp;
85         }
86         else {
87             /* haven't seen a -server yet */
88             if (!strcmp(tp, "-servers")) {
89                 inServer = 1;
90             }
91         }
92     }
93     if (!inServer) {
94         /* never saw a -server */
95         return UNOENT;
96     }
97     if (counter < MAXSERVERS) *aothers++ = 0;    /* null terminate if room */
98     return 0;
99 }
100
101 #ifdef AFS_PTHREAD_ENV
102 #include <pthread.h>
103 #include <assert.h>
104
105 static pthread_once_t random_once = PTHREAD_ONCE_INIT;
106 static int called_afs_random_once;
107 static pthread_key_t random_number_key; 
108
109 static void afs_random_once(void)
110 {
111     assert(pthread_key_create(&random_number_key, NULL)==0);
112     called_afs_random_once = 1;
113 }
114
115 #endif
116 /* 
117  * Random number generator and constants from KnuthV2 2d ed, p170
118  *
119  * Rules:
120  * X = (aX + c) % m
121  * m is a power of two 
122  * a % 8 is 5
123  * a is 0.73m  should be 0.01m .. 0.99m
124  * c is more or less immaterial.  1 or a is suggested.
125  *
126  * NB:  LOW ORDER BITS are not very random.  To get small random numbers,
127  *      treat result as <1, with implied binary point, and multiply by 
128  *      desired modulus.
129  * NB:  Has to be unsigned, since shifts on signed quantities may preserve
130  *      the sign bit.
131  * 
132  * In this case, m == 2^32, the mod operation is implicit. a == pi, which
133  * is used because it has some interesting characteristics (lacks any
134  * interesting bit-patterns).   
135  * 
136  */
137
138 /* 
139  * use time and pid to try to get some initial randomness.
140  */
141 #if !defined(UKERNEL)
142 #define ranstage(x)     (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
143
144 unsigned int afs_random(void)
145 {
146 #ifdef AFS_PTHREAD_ENV
147     afs_uint32 state;
148
149     (called_afs_random_once || pthread_once(&random_once, afs_random_once));
150     state = (afs_uint32) pthread_getspecific(random_number_key);
151 #else
152     static afs_uint32 state = 0;
153 #endif
154
155     if (!state) {
156         int i;
157         state = time(0) + getpid();
158         for (i=0;i<15;i++) {
159             ranstage(state);
160         }
161     }
162
163     ranstage(state);
164 #ifdef AFS_PTHREAD_ENV
165     pthread_setspecific(random_number_key, (const void *) state);
166 #endif
167     return (state);
168
169 }
170
171 /*
172  * returns int 0..14 using the high bits of a pseudo-random number instead of
173  * the low bits, as the low bits are "less random" than the high ones...
174  * slight roundoff error exists, an excercise for the reader.
175  * need to multiply by something with lots of ones in it, so multiply by 
176  * 8 or 16 is right out.
177  */
178
179 static unsigned int afs_randomMod15(void)
180 {
181     afs_uint32 temp;
182
183     temp = afs_random() >> 4;
184     temp = (temp *15) >> 28;
185
186     return temp;
187 }
188 #endif /* !defined(UKERNEL) */
189
190 #ifdef abs
191 #undef abs
192 #endif /* abs */
193 #define abs(a) ((a) < 0 ? -1*(a) : (a))
194 int ubik_ClientInit(
195   register struct rx_connection **serverconns,
196   struct ubik_client **aclient)
197 {
198     int i,j;
199     int count;
200     int offset;
201     register struct ubik_client *tc;
202
203     initialize_U_error_table();
204
205     if ( *aclient ) {   /* the application is doing a re-initialization*/
206         LOCK_UBIK_CLIENT((*aclient))
207         /* this is an important defensive check */
208         if ( ! ((*aclient)->initializationState) ) {
209             UNLOCK_UBIK_CLIENT((*aclient))
210             return UREINITIALIZE;
211         }
212
213         /* release all existing connections */
214         for (tc = *aclient, i=0; i<MAXSERVERS; i++) 
215         {
216             struct rx_connection *rxConn = ubik_GetRPCConn(tc,i);
217             if (rxConn == 0) break;
218 #ifdef AFS_PTHREAD_ENV
219             rx_ReleaseCachedConnection(rxConn);
220 #else
221             rx_DestroyConnection (rxConn);
222 #endif
223         }
224         UNLOCK_UBIK_CLIENT((*aclient))
225 #ifdef AFS_PTHREAD_ENV
226         if (pthread_mutex_destroy(&((*aclient)->cm))) return UMUTEXDESTROY;
227 #endif
228     } else {
229         tc = (struct ubik_client *) malloc(sizeof(struct ubik_client));
230     }
231     if (tc == NULL) return UNOMEM;
232     memset((void *) tc, 0, sizeof(*tc));
233 #ifdef AFS_PTHREAD_ENV
234     if (pthread_mutex_init(&(tc->cm), (const pthread_mutexattr_t*)0)) {
235         return UMUTEXINIT;
236     }
237 #endif
238     tc->initializationState = ++ubik_initializationState;
239
240     /* first count the # of server conns so we can randomize properly */
241     count = 0;
242     for(i=0;i<MAXSERVERS;i++) {
243         if (serverconns[i] == (struct rx_connection *) 0) break;
244         count++;
245     }
246
247     /* here count is the # of servers we're actually passed in.  Compute
248      * offset, a number between 0..count-1, where we'll start copying from the
249      * client-provided array. */
250     for (i=0; i< count; i++) {
251         offset = afs_randomMod15() % count;
252         for (j=abs(offset); j<2*count; j++) {
253             if (!tc->conns[abs(j%count)]) {
254                 tc->conns[abs(j%count)] = serverconns[i];
255                 break;
256             }
257         }
258     }
259
260     *aclient = tc;
261     return 0;
262 }
263
264 /* 
265  * ubik_ClientDestroy - destroys a ubik connection.  It calls rx to destroy the
266  * component rx connections, then frees the ubik connection structure.
267  */
268
269 afs_int32 ubik_ClientDestroy(struct ubik_client *aclient)
270 {
271     register int c;
272
273     if (aclient == 0) return 0;
274     LOCK_UBIK_CLIENT(aclient);
275     for (c=0; c<MAXSERVERS; c++) {
276         struct rx_connection *rxConn = ubik_GetRPCConn(aclient,c);
277         if (rxConn == 0) break;
278 #ifdef AFS_PTHREAD_ENV
279         rx_ReleaseCachedConnection(rxConn);
280 #else
281         rx_DestroyConnection (rxConn);
282 #endif
283     }
284     aclient->initializationState = 0; /* client in not initialized*/
285     UNLOCK_UBIK_CLIENT(aclient);
286 #ifdef AFS_PTHREAD_ENV
287     pthread_mutex_destroy(&(aclient->cm)); /* ignore failure */
288 #endif
289     free (aclient);
290     return 0;
291 }
292
293 /*
294  * RefreshConn -- So that intermittent failures that cause connections to die
295  *     don't kill whole ubik connection, refresh them when the connection is in
296  *     error.
297  */
298
299 static struct rx_connection *RefreshConn(struct rx_connection *tc)
300 {
301     afs_uint32 host;
302     u_short port;
303     u_short service;
304     struct rx_securityClass *sc;
305     int si;
306     struct rx_connection *newTc;
307
308     host = rx_HostOf(rx_PeerOf(tc));
309     port = rx_PortOf(rx_PeerOf(tc));
310     service = rx_ServiceIdOf(tc);
311     sc = rx_SecurityObjectOf(tc);
312     si = rx_SecurityClassOf(tc);
313
314     /*
315      * destroy old one after creating new one so that refCount on security
316      * object cannot reach zero.
317      */
318     newTc = rx_NewConnection (host, port, service, sc, si);
319     rx_DestroyConnection (tc);
320     return newTc;
321 }
322
323 #ifdef AFS_PTHREAD_ENV
324
325 pthread_once_t ubik_client_once = PTHREAD_ONCE_INIT;
326 pthread_mutex_t ubik_client_mutex;
327 #define LOCK_UCLNT_CACHE \
328     assert(pthread_once(&ubik_client_once, ubik_client_init_mutex) == 0 && \
329            pthread_mutex_lock(&ubik_client_mutex)==0);
330 #define UNLOCK_UCLNT_CACHE assert(pthread_mutex_unlock(&ubik_client_mutex)==0);
331
332 void ubik_client_init_mutex() {
333     assert(pthread_mutex_init(&ubik_client_mutex, NULL) == 0);
334 }
335
336 #else
337
338 #define LOCK_UCLNT_CACHE
339 #define UNLOCK_UCLNT_CACHE
340
341 #endif
342
343 #define SYNCCOUNT 10
344 static int *calls_needsync[SYNCCOUNT]; /* proc calls that need the sync site */
345 static int synccount=0;
346
347 /*
348  * call this instead of stub and we'll guarantee to find a host that's up.
349  * in the future, we should also put in a protocol to find the sync site
350  */
351 afs_int32 ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8, p9,
352                 p10, p11, p12, p13, p14, p15, p16)
353   int (*aproc)();
354   register struct ubik_client *aclient;
355   afs_int32 aflags;
356   long p1;
357   long p2;
358   long p3;
359   long p4;
360   long p5;
361   long p6;
362   long p7;
363   long p8;
364   long p9;
365   long p10;
366   long p11;
367   long p12;
368   long p13;
369   long p14;
370   long p15;
371   long p16;
372 {
373     afs_int32 rcode, code, newHost, thisHost, i, count;
374     int chaseCount, pass, needsync, inlist, j;
375     struct rx_connection *tc;
376     struct rx_peer *rxp;
377     short       origLevel ;
378
379     if (!aclient) return UNOENT;
380     LOCK_UBIK_CLIENT(aclient);
381
382 restart:
383     origLevel = aclient->initializationState;
384     rcode = UNOSERVERS;
385     chaseCount = inlist = needsync = 0;
386
387     LOCK_UCLNT_CACHE
388     for (j=0; ((j<SYNCCOUNT) && calls_needsync[j]); j++) {
389         if (calls_needsync[j] == (int *)aproc) {
390             inlist = needsync = 1;
391             break;
392         }
393     }
394     UNLOCK_UCLNT_CACHE
395
396     /* 
397      * First  pass, we try all servers that are up.
398      * Second pass, we try all servers.
399      */
400     for (pass=0; pass<2; pass++) { /*p*/
401         /* For each entry in our servers list */
402         for (count=0; ;count++) { /*s*/
403
404             if (needsync) {
405                 /* Need a sync site. Lets try to quickly find it */
406                 if (aclient->syncSite) {
407                     newHost = aclient->syncSite; /* already in network order */
408                     aclient->syncSite = 0;       /* Will reset if it works */
409                 } else if (aclient->conns[3]) {
410                     /* If there are fewer than four db servers in a cell,
411                     * there's no point in making the GetSyncSite call.
412                     * At best, it's a wash. At worst, it results in more
413                     * RPCs than you would otherwise make.
414                     */
415                     tc = aclient->conns[count];
416                     if (tc && rx_ConnError(tc)) {
417                       aclient->conns[count] = tc = RefreshConn(tc);
418                     }
419                     if (!tc) break;
420                     code = VOTE_GetSyncSite(tc, &newHost);
421                     if ( aclient->initializationState != origLevel)
422                         goto restart; /* somebody did a ubik_ClientInit */
423                     if (code) newHost = 0;
424                     newHost = htonl(newHost);    /* convert to network order */
425                 } else {
426                     newHost = 0;
427                 }
428                 if (newHost) {
429                     /* position count at the appropriate slot in the client
430                     * structure and retry. If we can't find in slot, we'll
431                     * just continue through the whole list 
432                     */
433                     for (i=0; i<MAXSERVERS && aclient->conns[i]; i++) {
434                         rxp = rx_PeerOf(aclient->conns[i]);
435                         thisHost = rx_HostOf(rxp);
436                         if (!thisHost) break;
437                         if (thisHost == newHost) {
438                             if (chaseCount++ > 2) break; /* avoid loop asking */
439                             count = i;         /* this index is the sync site */
440                             break;
441                         }
442                     }
443                 }
444             } /*needsync*/
445
446             tc = aclient->conns[count];
447             if (tc && rx_ConnError(tc)) {
448               aclient->conns[count] = tc = RefreshConn(tc);
449             }
450             if (!tc) break;
451
452             if ((pass == 0) && (aclient->states[count] & CFLastFailed)) {
453                 continue; /* this guy's down */
454             }
455
456             rcode = (*aproc)(tc, p1,  p2,  p3,  p4,  p5,  p6,  p7,  p8,  p9,
457                              p10, p11, p12, p13, p14, p15, p16);
458             if ( aclient->initializationState != origLevel) {   
459                 /* somebody did a ubik_ClientInit */
460                 if ( rcode ) goto restart; /* call failed */
461                 else    goto done;    /* call suceeded */
462             }
463             if (rcode < 0) {                            /* network errors */
464                 aclient->states[count] |= CFLastFailed;  /* Mark serer down */
465             }
466             else if (rcode == UNOTSYNC) {
467                 needsync = 1;
468             }
469             else if (rcode != UNOQUORUM) {
470                 /* either misc ubik code, or misc appl code, or success. */
471                 aclient->states[count] &= ~CFLastFailed;    /* mark server up */
472                 goto done;                                  /* all done */
473             }
474         } /*s*/
475     } /*p*/
476
477   done:
478     if (needsync) {
479         if (!inlist) {   /* Remember proc call that needs sync site */
480             LOCK_UCLNT_CACHE
481             calls_needsync[synccount % SYNCCOUNT] = (int *)aproc;
482             synccount++;
483             UNLOCK_UCLNT_CACHE
484             inlist = 1;
485         }
486         if (!rcode) {    /* Remember the sync site - cmd successful */
487             rxp = rx_PeerOf(aclient->conns[count]);
488             aclient->syncSite = rx_HostOf(rxp);
489         }
490     }
491     UNLOCK_UBIK_CLIENT(aclient);
492     return rcode;
493 }
494
495
496
497 /*
498  * call this after getting back a UNOTSYNC 
499  * note that getting a UNOTSYNC error code back does *not* guarantee
500  * that there is a sync site yet elected.  However, if there is a sync
501  * site out there somewhere, and you're trying an operation that
502  * requires a sync site, ubik will return UNOTSYNC, indicating the
503  * operation won't work until you find a sync site
504  */
505 static int try_GetSyncSite(register struct ubik_client *aclient, afs_int32 apos) {
506     struct rx_peer *rxp;
507     afs_int32 code;
508     int i;
509     afs_int32 thisHost, newHost;
510     struct rx_connection *tc;
511     short origLevel;
512
513     origLevel = aclient->initializationState;
514
515     /* get this conn */
516     tc = aclient->conns[apos];
517     if (tc && rx_ConnError (tc)) {
518         aclient->conns[apos] = (tc = RefreshConn (tc));
519     }
520     if (!tc) {
521         return -1;
522     }
523
524     /* now see if we can find the sync site host */
525     code = VOTE_GetSyncSite(tc, &newHost);
526     if ( aclient->initializationState != origLevel) {
527         return -1; /* somebody did a ubik_ClientInit */
528     }
529
530     if ( !code && newHost ) {
531         newHost = htonl(newHost); /* convert back to network order */
532
533         /*
534          * position count at the appropriate slot in the client
535          * structure and retry. If we can't find in slot, we'll just
536          * continue through the whole list
537          */
538         for(i=0;i<MAXSERVERS;i++) {
539             rxp = rx_PeerOf(aclient->conns[i]);
540             thisHost = rx_HostOf(rxp);
541             if (!thisHost) {
542                 return -1;
543             }
544             else if (thisHost == newHost) {
545                 return i;       /* we were told to use this one */
546             }
547         }
548     }
549     return -1;
550 }
551
552 /* 
553  * Create an internal version of ubik_CallIter that takes an additional
554  * parameter - to indicate whether the ubik client handle has already
555  * been locked.
556  */
557
558 #define NEED_LOCK 1
559 #define NO_LOCK 0
560
561 static afs_int32 CallIter(aproc, aclient, aflags, apos, p1, p2, p3, p4, p5, p6,
562                       p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, needlock)
563   int (*aproc)();
564   register struct ubik_client *aclient;
565   afs_int32 aflags;
566   int *apos;
567   long p1;
568   long p2;
569   long p3;
570   long p4;
571   long p5;
572   long p6;
573   long p7;
574   long p8;
575   long p9;
576   long p10;
577   long p11;
578   long p12;
579   long p13;
580   long p14;
581   long p15;
582   long p16;
583   int needlock;
584 {
585     register afs_int32 code;
586     struct rx_connection *tc;
587     short origLevel;
588
589     if (needlock) {
590         LOCK_UBIK_CLIENT(aclient)
591     }
592     origLevel = aclient->initializationState;
593
594     code = UNOSERVERS;
595
596     while (*apos < MAXSERVERS)
597     {
598         /* tc is the next conn to try */
599         tc = aclient->conns[*apos];
600         if (!tc) {
601             if (needlock) {
602                 UNLOCK_UBIK_CLIENT(aclient)
603             }
604             return UNOSERVERS;
605         }
606
607         if (rx_ConnError (tc)) {
608             tc = RefreshConn (tc);
609             aclient->conns[*apos] = tc;
610         }
611
612         if ((aflags & UPUBIKONLY) && (aclient->states[*apos] & CFLastFailed)) {
613             (*apos)++;  /* try another one if this server is down */
614         }
615         else {
616             break;      /* this is the desired path */
617         }
618     }
619     if (*apos >= MAXSERVERS) {
620         if (needlock) {
621             UNLOCK_UBIK_CLIENT(aclient)
622         }
623         return UNOSERVERS;
624     }
625
626     code = (*aproc)(tc,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16);
627     if ( aclient->initializationState != origLevel) {
628         if (needlock) {
629             UNLOCK_UBIK_CLIENT(aclient)
630         }
631         return code; /* somebody did a ubik_ClientInit */
632     }
633
634     /* what should I do in case of UNOQUORUM ? */
635     if (code < 0) {
636         aclient->states[*apos] |= CFLastFailed;           /* network errors */
637     }
638     else {
639         /* either misc ubik code, or misc application code or success. */
640         aclient->states[*apos] &= ~CFLastFailed;          /* operation worked */
641     }
642
643     (*apos)++;
644     if (needlock) {
645         UNLOCK_UBIK_CLIENT(aclient)
646     }
647     return code;
648 }
649
650 /* 
651  * call this instead of stub and we'll guarantee to find a host that's up.
652  * in the future, we should also put in a protocol to find the sync site
653  */
654 afs_int32 ubik_Call_New(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8,
655                     p9, p10, p11, p12, p13, p14, p15, p16)
656   int (*aproc)();
657   register struct ubik_client *aclient;
658   afs_int32 aflags;
659   long p1;
660   long p2;
661   long p3;
662   long p4;
663   long p5;
664   long p6;
665   long p7;
666   long p8;
667   long p9;
668   long p10;
669   long p11;
670   long p12;
671   long p13;
672   long p14;
673   long p15;
674   long p16;
675
676     afs_int32 code, rcode;
677     afs_int32 count;
678     afs_int32 temp;
679     int pass;
680     int stepBack;
681     short origLevel;
682
683     LOCK_UBIK_CLIENT(aclient)
684 restart:
685     rcode = UNOSERVERS;
686     origLevel = aclient->initializationState;
687
688     /* Do two passes. First pass only checks servers known running */
689     for (aflags |= UPUBIKONLY, pass=0; pass<2; pass++, aflags &= ~UPUBIKONLY) {
690         stepBack = 0;
691         count = 0;
692         while (1) {
693             code = CallIter(aproc, aclient, aflags, &count, p1,p2,p3,p4,
694                             p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,NO_LOCK);
695             if ( code && ( aclient->initializationState != origLevel)) {
696                 goto restart;
697             }
698             if (code == UNOSERVERS) {
699                 break;
700             }
701             rcode = code;        /* remember code from last good call */
702
703             if (code == UNOTSYNC) {     /* means this requires a sync site */
704                 if (aclient->conns[3]) { /* don't bother unless 4 or more srv */
705                     temp = try_GetSyncSite(aclient, count);
706                     if ( aclient->initializationState != origLevel) {
707                         goto restart; /* somebody did a ubik_ClientInit */
708                     }
709                     if ((temp >= 0) && ((temp > count) || (stepBack++ <= 2))) {
710                         count = temp;       /* generally try to make progress */
711                     }
712                 }
713             }
714             else if ((code >= 0) && (code != UNOQUORUM)) {
715                 UNLOCK_UBIK_CLIENT(aclient)
716                 return code;  /* success or global error condition */
717             }
718         }
719     }
720     UNLOCK_UBIK_CLIENT(aclient)
721     return rcode;
722 }
723
724 /* 
725  * This is part of an iterator.  It doesn't handle finding sync sites
726  */
727 afs_int32 ubik_CallIter(aproc, aclient, aflags, apos, p1, p2, p3, p4, p5, p6, p7,
728                     p8, p9, p10, p11, p12, p13, p14, p15, p16)
729   int (*aproc)();
730   register struct ubik_client *aclient;
731   afs_int32 aflags;
732   int *apos;
733   long p1;
734   long p2;
735   long p3;
736   long p4;
737   long p5;
738   long p6;
739   long p7;
740   long p8;
741   long p9;
742   long p10;
743   long p11;
744   long p12;
745   long p13;
746   long p14;
747   long p15;
748   long p16;
749 {
750     return CallIter(aproc, aclient, aflags, apos, p1, p2, p3, p4, p5,
751                     p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16,
752                     NEED_LOCK);
753 }