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