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