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