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