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