a259809ee4e3d2f99f1da5a9c1cf7e88ed2691e8
[openafs.git] / src / libadmin / adminutil / afs_utilAdmin.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 RCSID
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <afs/afs_Admin.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <afs/afs_Admin.h>
21 #include "afs_AdminInternal.h"
22 #include "afs_utilAdmin.h"
23 #include <afs/pthread_glock.h>
24 #include <afs/cellconfig.h>
25 #include <afs/dirpath.h>
26 #include <afs/com_err.h>
27 #include <afs/kautils.h>
28 #include <afs/cmd.h>
29 #include <afs/vlserver.h>
30 #include <afs/pterror.h>
31 #include <afs/bnode.h>
32 #include <afs/volser.h>
33 #include <afs/afsint.h>
34 #include <rx/rx.h>
35 #include <rx/rxstat.h>
36 #ifdef AFS_NT40_ENV
37 #include <winsock2.h>
38 #else
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 #endif
45
46 /*
47  * AIX 4.2 has PTHREAD_CREATE_UNDETACHED and not PTHREAD_CREATE_JOINABLE
48  *
49  * This fix should be done more centrally, but there's no time right now.
50  */
51 #if defined(AFS_AIX_ENV)
52 # if !defined(PTHREAD_CREATE_JOINABLE) && defined(PTHREAD_CREATE_UNDETACHED)
53 #  define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED
54 # endif
55 #endif
56
57 #define ERRCODE_RANGE 8
58 static pthread_once_t error_init_once = PTHREAD_ONCE_INIT;
59 static int error_init_done;
60
61 static void
62 init_once(void)
63 {
64
65     initialize_KA_error_table();
66     initialize_RXK_error_table();
67     initialize_KTC_error_table();
68     initialize_ACFG_error_table();
69     initialize_CMD_error_table();
70     initialize_VL_error_table();
71     initialize_PT_error_table();
72     initialize_BZ_error_table();
73     initialize_U_error_table();
74     initialize_AB_error_table();
75     initialize_AF_error_table();
76     initialize_AL_error_table();
77     initialize_AC_error_table();
78     initialize_AK_error_table();
79     initialize_AM_error_table();
80     initialize_AP_error_table();
81     initialize_AU_error_table();
82     initialize_AV_error_table();
83     initialize_VOLS_error_table();
84     error_init_done = 1;
85 }
86
87 int ADMINAPI
88 util_AdminErrorCodeTranslate(afs_status_t errorCode, int langId,
89                              const char **errorTextP, afs_status_p st)
90 {
91     int rc = 0;
92     afs_status_t tst = 0;
93     afs_int32 code;
94
95     if (errorTextP == NULL) {
96         tst = ADMUTILERRORTEXTPNULL;
97         goto fail_util_AdminErrorCodeTranslate;
98     }
99
100     /*
101      * Translate the error
102      */
103
104     if (!error_init_done)
105         pthread_once(&error_init_once, init_once);
106     code = (afs_int32) errorCode;
107     *errorTextP = error_message(code);
108     rc = 1;
109
110   fail_util_AdminErrorCodeTranslate:
111
112     if (st != NULL) {
113         *st = tst;
114     }
115     return rc;
116 }
117
118 /*
119  * The iterator functions and data for the database server retrieval functions.
120  */
121
122 typedef struct database_server_get {
123     int total;
124     int index;
125     struct afsconf_dir *conf;
126     struct afsconf_cell cell;
127     util_databaseServerEntry_t server[CACHED_ITEMS];
128 } database_server_get_t, *database_server_get_p;
129
130 static int
131 GetDatabaseServerRPC(void *rpc_specific, int slot, int *last_item,
132                      int *last_item_contains_data, afs_status_p st)
133 {
134     int rc = 0;
135     afs_status_t tst = 0;
136     database_server_get_p serv = (database_server_get_p) rpc_specific;
137
138     serv->server[slot].serverAddress =
139         ntohl(serv->cell.hostAddr[serv->index].sin_addr.s_addr);
140     strcpy(serv->server[slot].serverName, serv->cell.hostName[serv->index]);
141     serv->index++;
142
143     /*
144      * See if we've processed all the entries
145      */
146
147     if (serv->index == serv->total) {
148         *last_item = 1;
149         *last_item_contains_data = 1;
150     }
151     rc = 1;
152
153     if (st != NULL) {
154         *st = tst;
155     }
156     return rc;
157 }
158
159 static int
160 GetDatabaseServerFromCache(void *rpc_specific, int slot, void *dest,
161                            afs_status_p st)
162 {
163     int rc = 0;
164     afs_status_t tst = 0;
165     database_server_get_p serv = (database_server_get_p) rpc_specific;
166
167     memcpy(dest, (const void *)&serv->server[slot],
168            sizeof(util_databaseServerEntry_t));
169
170     rc = 1;
171     if (st != NULL) {
172         *st = tst;
173     }
174     return rc;
175 }
176
177 static int
178 DestroyDatabaseServer(void *rpc_specific, afs_status_p st)
179 {
180     int rc = 0;
181     afs_status_t tst = 0;
182     database_server_get_p serv = (database_server_get_p) rpc_specific;
183
184     afsconf_Close(serv->conf);
185     rc = 1;
186
187     if (st != NULL) {
188         *st = tst;
189     }
190     return rc;
191 }
192
193 /*
194  * util_DatabaseServerGetBegin - begin iterating over the database
195  * server machines in a cell.
196  *
197  * PARAMETERS
198  *
199  * IN cellName - the cell where database servers reside.
200  *
201  * OUT iterationIdP - upon successful completion contains an iterator that
202  * can be passed to util_DatabaseServerGetNext.
203  *
204  * LOCKS
205  *
206  * No locks are obtained or released by this function
207  *
208  * CAUTIONS
209  *
210  * None.
211  *
212  * RETURN CODES
213  *
214  * Returns != 0 upon successful completion.
215  */
216
217 int ADMINAPI
218 util_DatabaseServerGetBegin(const char *cellName, void **iterationIdP,
219                             afs_status_p st)
220 {
221     int rc = 0;
222     afs_status_t tst = 0;
223     afs_admin_iterator_p iter =
224         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
225     database_server_get_p serv =
226         (database_server_get_p) calloc(1, sizeof(database_server_get_t));
227     char copyCell[MAXCELLCHARS];
228
229     /*
230      * Validate arguments
231      */
232
233     if ((cellName == NULL) || (*cellName == 0)) {
234         tst = ADMUTILCELLNAMENULL;
235         goto fail_util_DatabaseServerGetBegin;
236     }
237
238     if (iterationIdP == NULL) {
239         goto fail_util_DatabaseServerGetBegin;
240     }
241
242     if ((iter == NULL) || (serv == NULL)) {
243         tst = ADMNOMEM;
244         goto fail_util_DatabaseServerGetBegin;
245     }
246
247     /*
248      * Fill in the serv structure
249      */
250
251     serv->conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
252     if (serv->conf == NULL) {
253         tst = ADMUTILCANTOPENCELLSERVDB;
254         goto fail_util_DatabaseServerGetBegin;
255     }
256
257     /*
258      * We must copy the cellname because afsconf_GetCellInfo
259      * actually writes over the cell name it is passed.
260      */
261     strncpy(copyCell, cellName, MAXCELLCHARS - 1);
262     tst =
263         afsconf_GetCellInfo(serv->conf, copyCell, AFSCONF_KAUTHSERVICE,
264                             &serv->cell);
265     if (tst != 0) {
266         goto fail_util_DatabaseServerGetBegin;
267     }
268
269     serv->total = serv->cell.numServers;
270     if (IteratorInit
271         (iter, (void *)serv, GetDatabaseServerRPC, GetDatabaseServerFromCache,
272          NULL, DestroyDatabaseServer, &tst)) {
273         *iterationIdP = (void *)iter;
274     } else {
275         goto fail_util_DatabaseServerGetBegin;
276     }
277     rc = 1;
278
279   fail_util_DatabaseServerGetBegin:
280
281     if (rc == 0) {
282         if (iter != NULL) {
283             free(iter);
284         }
285         if (serv != NULL) {
286             free(serv);
287         }
288     }
289
290     if (st != NULL) {
291         *st = tst;
292     }
293     return rc;
294 }
295
296 /*
297  * util_DatabaseServerGetNext - get the next server address.
298  *
299  * PARAMETERS
300  *
301  * IN iterationId - an iterator returned by util_DatabaseServerGetBegin
302  *
303  * OUT serverAddressP - upon successful completion contains the next 
304  * server address in the cell.
305  *
306  * LOCKS
307  *
308  * This function locks the iterator for the duration of its processing.
309  *
310  * CAUTIONS
311  *
312  * None.
313  *
314  * RETURN CODES
315  *
316  * Returns != 0 upon successful completion.
317  */
318
319
320 int ADMINAPI
321 util_DatabaseServerGetNext(const void *iterationId,
322                            util_databaseServerEntry_p serverP,
323                            afs_status_p st)
324 {
325     int rc = 0;
326     afs_status_t tst = 0;
327     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
328
329     if (iter == NULL) {
330         tst = ADMITERATORNULL;
331         goto fail_util_DatabaseServerGetNext;
332     }
333
334     if (serverP == NULL) {
335         tst = ADMUTILSERVERADDRESSPNULL;
336         goto fail_util_DatabaseServerGetNext;
337     }
338
339     rc = IteratorNext(iter, (void *)serverP, &tst);
340
341   fail_util_DatabaseServerGetNext:
342
343     if (st != NULL) {
344         *st = tst;
345     }
346     return rc;
347 }
348
349 /*
350  * util_DatabaseServerGetDone - stop using a database iterator.
351  *
352  * PARAMETERS
353  *
354  * IN iterationId - an iterator returned by util_DatabaseServerGetBegin
355  *
356  * LOCKS
357  *
358  * This function locks the iterator for the duration of its processing.
359  * And then destroys it before returning.
360  *
361  * CAUTIONS
362  *
363  * None.
364  *
365  * RETURN CODES
366  *
367  * Returns != 0 upon successful completion.
368  */
369
370 int ADMINAPI
371 util_DatabaseServerGetDone(const void *iterationId, afs_status_p st)
372 {
373     int rc = 0;
374     afs_status_t tst = 0;
375     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
376
377     /*
378      * Validate parameters
379      */
380
381     if (iter == NULL) {
382         tst = ADMITERATORNULL;
383         goto fail_util_DatabaseServerGetDone;
384     }
385
386     rc = IteratorDone(iter, &tst);
387
388   fail_util_DatabaseServerGetDone:
389
390     if (st != NULL) {
391         *st = tst;
392     }
393     return rc;
394 }
395
396 /*
397  * GetServerAddressFromName - translate a character string server name
398  * to an integer representation of an IP address.
399  *
400  * PARAMETERS
401  *
402  * IN serverName - the character string server name in either foo.com
403  * format, or 123.12.1.1 format.
404  *
405  * OUT serverAddress - an integer that is filled with the correct address
406  * in host byte order upon successful completion.
407  *
408  * LOCKS
409  * 
410  * No locks are obtained or released by this function
411  *
412  * CAUTIONS
413  *
414  * On many platforms, gethostbyname is not thread safe.  Since we are
415  * only working under NT for now I'll use it directly.  In future UNIX
416  * ports, a wrapper function should be written to call the correct function
417  * on the particular platform.
418  * 
419  * RETURN CODES
420  *
421  * Returns != 0 upon successful completion.
422  */
423
424 int ADMINAPI
425 util_AdminServerAddressGetFromName(const char *serverName, int *serverAddress,
426                                    afs_status_p st)
427 {
428     int rc = 0;
429     afs_status_t tst = 0;
430     struct hostent *server;
431     int part1, part2, part3, part4;
432     int num_converted;
433
434     if ((serverName == NULL) || (*serverName == 0)) {
435         tst = ADMUTILSERVERNAMENULL;
436         goto fail_util_AdminServerAddressGetFromName;
437     }
438
439     if (serverAddress == NULL) {
440         tst = ADMUTILSERVERADDRESSNULL;
441         goto fail_util_AdminServerAddressGetFromName;
442     }
443
444     num_converted =
445         sscanf(serverName, "%d.%d.%d.%d", &part1, &part2, &part3, &part4);
446     if (num_converted == 4) {
447         *serverAddress = (part1 << 24) | (part2 << 16) | (part3 << 8) | part4;
448     } else {
449         LOCK_GLOBAL_MUTEX;
450         server = gethostbyname(serverName);
451         if (server != NULL) {
452             memcpy((void *)serverAddress, (const void *)server->h_addr,
453                    sizeof(serverAddress));
454             *serverAddress = ntohl(*serverAddress);
455         } else {
456             tst = ADMUTILCANTGETSERVERNAME;
457             UNLOCK_GLOBAL_MUTEX;
458             goto fail_util_AdminServerAddressGetFromName;
459         }
460         UNLOCK_GLOBAL_MUTEX;
461     }
462     rc = 1;
463
464   fail_util_AdminServerAddressGetFromName:
465
466     if (st != NULL) {
467         *st = tst;
468     }
469
470     return rc;
471 }
472
473 /*
474  * This file contains functions that can be used to create iterator
475  * functions within the api.  I have attempted to make these functions
476  * generic so that they can be used across the admin components.
477  *
478  * The functions in this file are a generalized producer/consumer
479  * implementation.  They manage access to a queue of data.  The only
480  * assumption these functions make about this data is that it is 
481  * stored in a queue which is implemented via an array.  These functions
482  * know about the index into the array, but they know nothing about
483  * the contents of the array.
484  *
485  * The data specific functions you implement will have to create some
486  * data specific storage structure that will have an array
487  * of size CACHED_ITEMS data items.  This structure will also need to
488  * store any necessary parameters/state variables you need to issue the
489  * rpc to retrieve the next item.
490  *
491  * In order to use the generic functions, you must implement four functions
492  * for each type of data you wish to retrieve.  The functions are:
493  *
494  * validate_specific_data_func - this function is handed a void pointer
495  * that points to the rpc specific data you've allocated.  The function
496  * should examine the data for validity and return an appropriate error.
497  * This function is called every time the iterator is validated.
498  *
499  * destroy_specific_data_func - this function is handed a void pointer
500  * that points to the rpc specific data you've allocated.  It should
501  * destroy any components of the specific data as required and then
502  * return.  The void pointer is free'd by the generic functions.
503  *
504  * get_cached_data_func - this function is handed a void pointer 
505  * that points to the rpc specific data you've allocated, an index
506  * into the cache of the item to be copied to the caller, and a void
507  * pointer where the cache item should be copied.
508  *
509  * make_rpc_func - this function is handed a void pointer that points
510  * to the rpc specific data you've allocated, an index into the cache
511  * of the item to be filled with the next retrieved item, and an int
512  * pointer that should be set to 1 if there are no more items to be
513  * retrieved.  The assumption made by the generic functions is that 
514  * the last_item status requires an individual rpc - the data isn't 
515  * piggybacked on the last data item.
516  */
517
518 /*
519  * IteratorDelete - delete an iterator.
520  *
521  * PARAMETERS
522  *
523  * IN interator - the iterator to delete.
524  *
525  * LOCKS
526  *
527  * No locks are held by this function.
528  *
529  * RETURN CODES
530  *
531  * Returns != 0 upon successful completion.
532  */
533
534 static int
535 IteratorDelete(afs_admin_iterator_p iter, afs_status_p st)
536 {
537     int rc = 0;
538     afs_status_t tst = 0;
539
540     if (pthread_mutex_destroy(&iter->mutex)) {
541         tst = ADMMUTEXDESTROY;
542         goto fail_IteratorDelete;
543     }
544     if (pthread_cond_destroy(&iter->add_item)) {
545         tst = ADMCONDDESTROY;
546         goto fail_IteratorDelete;
547     }
548     if (pthread_cond_destroy(&iter->remove_item)) {
549         tst = ADMCONDDESTROY;
550         goto fail_IteratorDelete;
551     }
552     iter->is_valid = 0;
553     if (iter->destroy_specific != NULL) {
554         iter->destroy_specific(iter->rpc_specific, &tst);
555     }
556     free(iter->rpc_specific);
557     free(iter);
558     rc = 1;
559
560   fail_IteratorDelete:
561
562     if (st != NULL) {
563         *st = tst;
564     }
565     return rc;
566 }
567
568 /*
569  * DataGet - the background thread that is spawned for every
570  * IteratorBegin call that is successful.  This thread tries
571  * to fetch the data from the server ahead of the
572  * IteratorNext calls.
573  *
574  * PARAMETERS
575  *
576  * IN arg - the address of the iterator structure to be used for this
577  * iteration.
578  *
579  * LOCKS
580  *
581  * The iterator mutex is used by this function to protect elements
582  * of the iterator structure.
583  *
584  * RETURN CODES
585  *
586  * Returns != 0 upon successful completion.
587  */
588
589 static void *
590 DataGet(void *arg)
591 {
592     afs_admin_iterator_p iter = (afs_admin_iterator_p) arg;
593     void *rc = 0;
594     afs_status_t tst = 0;
595     int mutex_locked = 0;
596     int last_item = 0;
597     int last_item_contains_data = 0;
598
599     if (pthread_mutex_lock(&iter->mutex)) {
600         iter->st = ADMMUTEXLOCK;
601         goto fail_DataGet;
602     }
603
604     mutex_locked = 1;
605
606     while (1) {
607
608         /*
609          * Check to see if there's room for this datum.  If not, wait
610          * on the consumer to free up another slot.
611          */
612
613         while (iter->cache_slots_used == CACHED_ITEMS) {
614             if (pthread_cond_wait(&iter->remove_item, &iter->mutex)) {
615                 iter->st = ADMCONDWAIT;
616                 goto fail_DataGet;
617             }
618         }
619
620         /*
621          * Check to see if someone called Done and terminated the request.
622          * We could have gone to sleep above when the buffer was full and
623          * instead of being awoken because another slot is open, we were
624          * awoken because the request was terminated.
625          */
626
627         if (iter->request_terminated) {
628             goto fail_DataGet;
629         }
630
631         if (pthread_mutex_unlock(&iter->mutex)) {
632             iter->st = ADMMUTEXUNLOCK;
633             goto fail_DataGet;
634         }
635
636         mutex_locked = 0;
637
638         /*
639          * Make an rpc without holding the iter mutex
640          * We reference an item in the principal cache here without
641          * holding the mutex.  This is safe because:
642          * 1. The iter structure is ref counted and won't be deleted
643          *    from underneath us.
644          * 2. cache_queue_tail is always one item ahead of the consumer
645          *    thread so we are the only thread accessing this member.
646          */
647
648         iter->make_rpc(iter->rpc_specific, iter->cache_queue_tail, &last_item,
649                        &last_item_contains_data, &tst);
650
651         if (pthread_mutex_lock(&iter->mutex)) {
652             iter->st = ADMMUTEXLOCK;
653             goto fail_DataGet;
654         }
655
656         mutex_locked = 1;
657
658         /*
659          * Check to see if someone called Done and terminated the request
660          */
661
662         if (iter->request_terminated) {
663             goto fail_DataGet;
664         }
665
666         /*
667          * Check the rc of the rpc, and see if there are no more items
668          * to be retrieved.
669          */
670
671         if (tst != 0) {
672             iter->st = tst;
673             goto fail_DataGet;
674         }
675
676         /*
677          * Check to see if this is the last item produced by the rpc.
678          * If it isn't, add the item to the cache and proceed.
679          * If it is, check to see if the last item contains valid data.
680          *     If it contains valid data, we need to add it to our cache.
681          *     If it doesn't, we mark the iterator as complete.
682          */
683
684         if ((!last_item) || ((last_item) && (last_item_contains_data))) {
685             iter->cache_queue_tail =
686                 (iter->cache_queue_tail + 1) % CACHED_ITEMS;
687             iter->cache_slots_used++;
688         }
689         if (last_item) {
690             iter->st = ADMITERATORDONE;
691             iter->done_iterating = 1;
692             /*
693              * There's a small chance that the consumer emptied the
694              * cache queue while we were making the last rpc and has
695              * since gone to sleep waiting for more data.  In this case
696              * there will never be more data so we signal him here.
697              */
698             pthread_cond_signal(&iter->add_item);
699             goto fail_DataGet;
700         }
701
702
703         /*
704          * If the cache was empty and we just added another item, signal
705          * the consumer
706          */
707
708         if (iter->cache_slots_used == 1) {
709             if (pthread_cond_signal(&iter->add_item)) {
710                 iter->st = ADMCONDSIGNAL;
711                 goto fail_DataGet;
712             }
713         }
714     }
715
716
717   fail_DataGet:
718
719     /*
720      * If we are exiting with an error, signal the consumer in the event
721      * they were waiting for us to produce more data
722      */
723
724     if (tst != 0) {
725         pthread_cond_signal(&iter->add_item);
726     }
727
728     if (mutex_locked) {
729         pthread_mutex_unlock(&iter->mutex);
730     }
731
732     return rc;
733 }
734
735 /*
736  * IsValidIterator - verify the validity of a afs_admin_iterator_t.
737  *
738  * PARAMETERS
739  *
740  * IN interator - the interator to be verified.
741  *
742  * LOCKS
743  *
744  * We assume the iter->mutex lock is already held.
745  *
746  * RETURN CODES
747  *
748  * Returns != 0 upon successful completion.
749  */
750
751 static int
752 IsValidIterator(const afs_admin_iterator_p iterator, afs_status_p st)
753 {
754     int rc = 0;
755     afs_status_t tst = 0;
756
757     /*
758      * Validate input parameters
759      */
760
761     if (iterator == NULL) {
762         tst = ADMITERATORNULL;
763         goto fail_IsValidIterator;
764     }
765
766     if ((iterator->begin_magic != BEGIN_MAGIC)
767         || (iterator->end_magic != END_MAGIC)) {
768         tst = ADMITERATORBADMAGICNULL;
769         goto fail_IsValidIterator;
770     }
771
772     if (iterator->is_valid == 0) {
773         tst = ADMITERATORINVALID;
774         goto fail_IsValidIterator;
775     }
776
777     /*
778      * Call the iterator specific validation function
779      */
780
781     if (iterator->validate_specific != NULL) {
782         if (!iterator->validate_specific(iterator->rpc_specific, &tst)) {
783             goto fail_IsValidIterator;
784         }
785     }
786     rc = 1;
787
788   fail_IsValidIterator:
789
790     if (st != NULL) {
791         *st = tst;
792     }
793     return rc;
794 }
795
796 /*
797  * IteratorNext - return the next datum in an interator.
798  *
799  * PARAMETERS
800  *
801  * IN interator - the iterator containing the data.
802  *
803  * IN dest - the address where the data should be copied.
804  *
805  * LOCKS
806  *
807  * Lock the iterator upon entry, and hold it during the duration of this
808  * function.
809  *
810  * RETURN CODES
811  *
812  * Returns != 0 upon successful completion.
813  */
814
815 int
816 IteratorNext(afs_admin_iterator_p iter, void *dest, afs_status_p st)
817 {
818     int rc = 0;
819     afs_status_t tst = 0;
820     int locked_iter = 0;
821
822     /*
823      * We have to lock the iterator before we validate it
824      */
825
826     if (pthread_mutex_lock(&iter->mutex)) {
827         tst = ADMMUTEXLOCK;
828         goto fail_IteratorNext;
829     }
830
831     locked_iter = 1;
832
833     if (!IsValidIterator(iter, &tst)) {
834         goto fail_IteratorNext;
835     }
836
837     if (iter->request_terminated == 1) {
838         tst = ADMITERATORTERMINATED;
839         goto fail_IteratorNext;
840     }
841
842     if ((iter->st != AFS_STATUS_OK) && (iter->st != ADMITERATORDONE)) {
843         tst = iter->st;
844         goto fail_IteratorNext;
845     }
846
847     /*
848      * Check to see if there are any queue'd items.  If not, wait here
849      * until signalled by the producer.
850      */
851
852     while (iter->cache_slots_used == 0) {
853
854         /*
855          * Maybe the producer experienced an rpc failure.
856          */
857
858         if ((!iter->done_iterating) && (iter->st != 0)) {
859             tst = iter->st;
860             goto fail_IteratorNext;
861         }
862
863         /*
864          * Maybe there are no queue'd items because the producer is done
865          */
866
867         if (iter->done_iterating) {
868             tst = iter->st;
869             goto fail_IteratorNext;
870         }
871
872         if (pthread_cond_wait(&iter->add_item, &iter->mutex)) {
873             tst = ADMCONDWAIT;
874             goto fail_IteratorNext;
875         }
876     }
877
878     /*
879      * Copy the next cached item and update the cached item count
880      * and the index into the cache array
881      */
882
883     if (!iter->
884         get_cached_data(iter->rpc_specific, iter->cache_queue_head, dest,
885                         &tst)) {
886         goto fail_IteratorNext;
887     }
888
889     iter->cache_queue_head = (iter->cache_queue_head + 1) % CACHED_ITEMS;
890     iter->cache_slots_used--;
891
892     /*
893      * If the cache was full before we removed the item above, the
894      * producer may have been waiting for us to remove an item.
895      * Signal the producer letting him know that we've opened a slot
896      * in the cache
897      */
898
899     if (iter->cache_slots_used == (CACHED_ITEMS - 1)) {
900         if (pthread_cond_signal(&iter->remove_item)) {
901             tst = ADMCONDSIGNAL;
902             goto fail_IteratorNext;
903         }
904     }
905     rc = 1;
906
907
908   fail_IteratorNext:
909
910     if (locked_iter == 1) {
911         pthread_mutex_unlock(&iter->mutex);
912     }
913
914     if (st != NULL) {
915         *st = tst;
916     }
917     return rc;
918 }
919
920 /*
921  * IteratorDone - mark the iterator done.
922  *
923  * PARAMETERS
924  *
925  * IN interator - the iterator to mark done.
926  *
927  * LOCKS
928  *
929  * Lock the iterator upon entry, and hold it during the duration of this
930  * function.
931  *
932  * RETURN CODES
933  *
934  * Returns != 0 upon successful completion.
935  */
936
937 int
938 IteratorDone(afs_admin_iterator_p iter, afs_status_p st)
939 {
940     int rc = 0;
941     afs_status_t tst = 0;
942     int mutex_locked = 1;
943
944     if (pthread_mutex_lock(&iter->mutex)) {
945         tst = ADMMUTEXLOCK;
946         goto fail_IteratorDone;
947     }
948
949     mutex_locked = 1;
950
951
952     if (!IsValidIterator(iter, &tst)) {
953         goto fail_IteratorDone;
954     }
955
956
957     /*
958      * Depending upon the status of the background worker thread,
959      * we can either join with him immediately (if we know he has
960      * terminated), or we need to tell him the request has been
961      * terminated and then join with him.
962      */
963
964     if (!iter->done_iterating) {
965         iter->request_terminated = 1;
966         iter->cache_slots_used = 0;
967         pthread_cond_signal(&iter->remove_item);
968     }
969
970     /*
971      * We have to unlock the mutex to allow the background thread to
972      * progress
973      */
974
975     if (pthread_mutex_unlock(&iter->mutex)) {
976         tst = ADMMUTEXUNLOCK;
977         goto fail_IteratorDone;
978     }
979
980     if (iter->make_rpc != NULL) {
981         if (pthread_join(iter->bg_worker, (void **)0)) {
982             tst = ADMTHREADJOIN;
983             goto fail_IteratorDone;
984         }
985     }
986
987     /*
988      * We don't relock the mutex here since we are the only thread
989      * that has access to the iter now
990      */
991
992     rc = IteratorDelete(iter, &tst);
993     mutex_locked = 0;
994
995   fail_IteratorDone:
996
997     if (mutex_locked) {
998         pthread_mutex_unlock(&iter->mutex);
999     }
1000
1001     if (st != NULL) {
1002         *st = tst;
1003     }
1004     return rc;
1005 }
1006
1007 /*
1008  * IteratorInit - initialize an iterator.
1009  *
1010  * PARAMETERS
1011  *
1012  * IN interator - the iterator to initialize.
1013  *
1014  * LOCKS
1015  *
1016  * No locks are held by this function.
1017  *
1018  * RETURN CODES
1019  *
1020  * Returns != 0 upon successful completion.
1021  */
1022
1023 int
1024 IteratorInit(afs_admin_iterator_p iter, void *rpc_specific,
1025              make_rpc_func make_rpc, get_cached_data_func get_cached_data,
1026              validate_specific_data_func validate_specific_data,
1027              destroy_specific_data_func destroy_specific_data,
1028              afs_status_p st)
1029 {
1030     int rc = 0;
1031     afs_status_t tst = 0;
1032     int mutex_inited = 0;
1033     int add_item_cond_inited = 0;
1034     int remove_item_cond_inited = 0;
1035
1036     if (iter == NULL) {
1037         tst = ADMITERATORNULL;
1038         goto fail_IteratorInit;
1039     }
1040
1041     if (rpc_specific == NULL) {
1042         tst = ADMITERATORRPCSPECIFICNULL;
1043         goto fail_IteratorInit;
1044     }
1045
1046     /*
1047      * Initialize the iterator structure
1048      */
1049     iter->begin_magic = BEGIN_MAGIC;
1050     iter->end_magic = END_MAGIC;
1051     iter->is_valid = 1;
1052     iter->cache_slots_used = 0;
1053     iter->done_iterating = 0;
1054     iter->request_terminated = 0;
1055     iter->st = AFS_STATUS_OK;
1056     iter->cache_queue_head = 0;
1057     iter->cache_queue_tail = 0;
1058     iter->cache_slots_used = 0;
1059     iter->rpc_specific = rpc_specific;
1060     iter->make_rpc = make_rpc;
1061     iter->get_cached_data = get_cached_data;
1062     iter->validate_specific = validate_specific_data;
1063     iter->destroy_specific = destroy_specific_data;
1064
1065     if (pthread_mutex_init(&iter->mutex, (const pthread_mutexattr_t *)0)) {
1066         tst = ADMMUTEXINIT;
1067         goto fail_IteratorInit;
1068     } else {
1069         mutex_inited = 1;
1070     }
1071
1072     if (pthread_cond_init(&iter->add_item, (const pthread_condattr_t *)0)) {
1073         tst = ADMCONDINIT;
1074         goto fail_IteratorInit;
1075     } else {
1076         add_item_cond_inited = 1;
1077     }
1078
1079     if (pthread_cond_init(&iter->remove_item, (const pthread_condattr_t *)0)) {
1080         tst = ADMCONDINIT;
1081         goto fail_IteratorInit;
1082     } else {
1083         remove_item_cond_inited = 1;
1084     }
1085
1086     /*
1087      * Create a worker thread that will begin to query the server
1088      * and cache responses.
1089      */
1090
1091     if (iter->make_rpc != NULL) {
1092         pthread_attr_t tattr;
1093
1094         if (pthread_attr_init(&tattr)) {
1095             tst = ADMTHREADATTRINIT;
1096             goto fail_IteratorInit;
1097         }
1098
1099         if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
1100             tst = ADMTHREADATTRSETDETACHSTATE;
1101             goto fail_IteratorInit;
1102         }
1103
1104         if (pthread_create(&iter->bg_worker, &tattr, DataGet, (void *)iter)) {
1105             tst = ADMTHREADCREATE;
1106             goto fail_IteratorInit;
1107         }
1108     }
1109     rc = 1;
1110
1111   fail_IteratorInit:
1112
1113     if (rc == 0) {
1114         if (mutex_inited) {
1115             pthread_mutex_destroy(&iter->mutex);
1116         }
1117         if (remove_item_cond_inited) {
1118             pthread_cond_destroy(&iter->remove_item);
1119         }
1120         if (add_item_cond_inited) {
1121             pthread_cond_destroy(&iter->add_item);
1122         }
1123     }
1124
1125     if (st != NULL) {
1126         *st = tst;
1127     }
1128     return rc;
1129 }
1130
1131 int ADMINAPI
1132 CellHandleIsValid(const void *cellHandle, afs_status_p st)
1133 {
1134     int rc = 0;
1135     afs_status_t tst = 0;
1136     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1137
1138     /*
1139      * Validate input parameters
1140      */
1141
1142     if (c_handle == NULL) {
1143         tst = ADMCLIENTCELLHANDLENULL;
1144         goto fail_CellHandleIsValid;
1145     }
1146
1147     if ((c_handle->begin_magic != BEGIN_MAGIC)
1148         || (c_handle->end_magic != END_MAGIC)) {
1149         tst = ADMCLIENTCELLHANDLEBADMAGIC;
1150         goto fail_CellHandleIsValid;
1151     }
1152
1153     if (c_handle->is_valid == 0) {
1154         tst = ADMCLIENTCELLINVALID;
1155         goto fail_CellHandleIsValid;
1156     }
1157     rc = 1;
1158
1159   fail_CellHandleIsValid:
1160
1161     if (st != NULL) {
1162         *st = tst;
1163     }
1164     return rc;
1165 }
1166
1167 /*
1168  * The iterator functions and data for the rpc statistic retrieval functions
1169  */
1170
1171 typedef struct rpc_stat_get {
1172     afs_uint32 clock_sec;
1173     afs_uint32 clock_usec;
1174     afs_uint32 index;
1175     afs_uint32 total;
1176     afs_uint32 clientVersion;
1177     afs_uint32 serverVersion;
1178     struct rpcStats stat_list;
1179     afs_RPCStats_t stats[CACHED_ITEMS];
1180     afs_uint32 *pointer;
1181 } rpc_stat_get_t, *rpc_stat_get_p;
1182
1183 static void
1184 UnmarshallRPCStats(afs_uint32 serverVersion, afs_uint32 ** ptrP,
1185                    afs_RPCUnion_p s)
1186 {
1187     afs_uint32 *ptr;
1188     unsigned int hi, lo;
1189
1190     /*
1191      * Server must always match lower versions. We are version 1.
1192      */
1193     ptr = *ptrP;
1194     s->stats_v1.remote_peer = *(ptr++);
1195     s->stats_v1.remote_port = *(ptr++);
1196     s->stats_v1.remote_is_server = *(ptr++);
1197     s->stats_v1.interfaceId = *(ptr++);
1198     s->stats_v1.func_total = *(ptr++);
1199     s->stats_v1.func_index = *(ptr++);
1200     hi = *(ptr++);
1201     lo = *(ptr++);
1202     hset64(s->stats_v1.invocations, hi, lo);
1203     hi = *(ptr++);
1204     lo = *(ptr++);
1205     hset64(s->stats_v1.bytes_sent, hi, lo);
1206     hi = *(ptr++);
1207     lo = *(ptr++);
1208     hset64(s->stats_v1.bytes_rcvd, hi, lo);
1209     s->stats_v1.queue_time_sum.sec = *(ptr++);
1210     s->stats_v1.queue_time_sum.usec = *(ptr++);
1211     s->stats_v1.queue_time_sum_sqr.sec = *(ptr++);
1212     s->stats_v1.queue_time_sum_sqr.usec = *(ptr++);
1213     s->stats_v1.queue_time_min.sec = *(ptr++);
1214     s->stats_v1.queue_time_min.usec = *(ptr++);
1215     s->stats_v1.queue_time_max.sec = *(ptr++);
1216     s->stats_v1.queue_time_max.usec = *(ptr++);
1217     s->stats_v1.execution_time_sum.sec = *(ptr++);
1218     s->stats_v1.execution_time_sum.usec = *(ptr++);
1219     s->stats_v1.execution_time_sum_sqr.sec = *(ptr++);
1220     s->stats_v1.execution_time_sum_sqr.usec = *(ptr++);
1221     s->stats_v1.execution_time_min.sec = *(ptr++);
1222     s->stats_v1.execution_time_min.usec = *(ptr++);
1223     s->stats_v1.execution_time_max.sec = *(ptr++);
1224     s->stats_v1.execution_time_max.usec = *(ptr++);
1225     *ptrP = ptr;
1226 }
1227
1228 static int
1229 GetRPCStatsRPC(void *rpc_specific, int slot, int *last_item,
1230                int *last_item_contains_data, afs_status_p st)
1231 {
1232     int rc = 0;
1233     afs_status_t tst = 0;
1234     rpc_stat_get_p t = (rpc_stat_get_p) rpc_specific;
1235
1236     t->stats[slot].clientVersion = t->clientVersion;
1237     t->stats[slot].serverVersion = t->serverVersion;
1238     t->stats[slot].statCount = t->total;
1239
1240     /*
1241      * If the server stat version is greater than or equal to my version
1242      * number, it is required to return the values in the client's current
1243      * format
1244      */
1245
1246     UnmarshallRPCStats(t->serverVersion, &t->pointer, &t->stats[slot].s);
1247
1248     t->index++;
1249
1250     /*
1251      * See if we've processed all the entries
1252      */
1253
1254     if (t->index == t->total) {
1255         *last_item = 1;
1256         *last_item_contains_data = 1;
1257     }
1258     rc = 1;
1259
1260     if (st != NULL) {
1261         *st = tst;
1262     }
1263     return rc;
1264 }
1265
1266 static int
1267 GetRPCStatsFromCache(void *rpc_specific, int slot, void *dest,
1268                      afs_status_p st)
1269 {
1270     int rc = 0;
1271     afs_status_t tst = 0;
1272     rpc_stat_get_p stat = (rpc_stat_get_p) rpc_specific;
1273
1274     memcpy(dest, (const void *)&stat->stats[slot], sizeof(afs_RPCStats_t));
1275
1276     rc = 1;
1277     if (st != NULL) {
1278         *st = tst;
1279     }
1280     return rc;
1281 }
1282
1283 static int
1284 DestroyRPCStats(void *rpc_specific, afs_status_p st)
1285 {
1286     int rc = 0;
1287     afs_status_t tst = 0;
1288     rpc_stat_get_p stat = (rpc_stat_get_p) rpc_specific;
1289
1290     if (stat->stat_list.rpcStats_val != NULL) {
1291         free(stat->stat_list.rpcStats_val);
1292     }
1293     rc = 1;
1294
1295     if (st != NULL) {
1296         *st = tst;
1297     }
1298     return rc;
1299 }
1300
1301 /*
1302  * util_RPCStatsGetBegin - begin retrieving rpc stats for a process
1303  *
1304  * PARAMETERS
1305  *
1306  * IN conn - an rx connection to the process to be queried
1307  *
1308  * IN rpc - the function to call to make the actual rpc
1309  *
1310  * OUT iterationIdP - an iteration id that can be passed to
1311  * util_RPCStatsGetNext to get the next rpc stat
1312  *
1313  * LOCKS
1314  *
1315  * No locks are obtained or released by this function
1316  *
1317  * RETURN CODES
1318  *
1319  * Returns != 0 upon successful completion.
1320  *
1321  */
1322
1323 int ADMINAPI
1324 util_RPCStatsGetBegin(struct rx_connection *conn, int (*rpc) (),
1325                       void **iterationIdP, afs_status_p st)
1326 {
1327     int rc = 0;
1328     afs_status_t tst = 0;
1329     afs_admin_iterator_p iter =
1330         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1331     rpc_stat_get_p stat = (rpc_stat_get_p) malloc(sizeof(rpc_stat_get_t));
1332
1333     if (conn == NULL) {
1334         tst = ADMRXCONNNULL;
1335         goto fail_util_RPCStatsGetBegin;
1336     }
1337
1338     if (rpc == NULL) {
1339         tst = ADMRPCPTRNULL;
1340         goto fail_util_RPCStatsGetBegin;
1341     }
1342
1343     if (iterationIdP == NULL) {
1344         tst = ADMITERATIONIDPNULL;
1345         goto fail_util_RPCStatsGetBegin;
1346     }
1347
1348     if ((iter == NULL) || (stat == NULL)) {
1349         tst = ADMNOMEM;
1350         goto fail_util_RPCStatsGetBegin;
1351     }
1352
1353     stat->stat_list.rpcStats_len = 0;
1354     stat->stat_list.rpcStats_val = 0;
1355     stat->index = 0;
1356     stat->clientVersion = RX_STATS_RETRIEVAL_VERSION;
1357
1358     tst =
1359         (*rpc) (conn, stat->clientVersion, &stat->serverVersion,
1360                 &stat->clock_sec, &stat->clock_usec, &stat->total,
1361                 &stat->stat_list);
1362
1363     if (tst != 0) {
1364         goto fail_util_RPCStatsGetBegin;
1365     }
1366
1367     /*
1368      * If there are no statistics, just mark the iterator done and
1369      * return.
1370      */
1371
1372     if (stat->stat_list.rpcStats_len == 0) {
1373         stat->pointer = NULL;
1374         if (!IteratorInit(iter, (void *)stat, NULL, NULL, NULL, NULL, &tst)) {
1375             goto fail_util_RPCStatsGetBegin;
1376         }
1377         iter->done_iterating = 1;
1378         iter->st = ADMITERATORDONE;
1379     } else {
1380         stat->pointer = stat->stat_list.rpcStats_val;
1381         if (!IteratorInit
1382             (iter, (void *)stat, GetRPCStatsRPC, GetRPCStatsFromCache, NULL,
1383              DestroyRPCStats, &tst)) {
1384             goto fail_util_RPCStatsGetBegin;
1385         }
1386     }
1387     *iterationIdP = (void *)iter;
1388     rc = 1;
1389
1390   fail_util_RPCStatsGetBegin:
1391
1392     if (rc == 0) {
1393         if (iter != NULL) {
1394             free(iter);
1395         }
1396         if (stat != NULL) {
1397             free(stat);
1398         }
1399     }
1400
1401     if (st != NULL) {
1402         *st = tst;
1403     }
1404     return rc;
1405 }
1406
1407 /*
1408  * util_RPCStatsGetNext - retrieve the next rpc stat from the server
1409  *
1410  * PARAMETERS
1411  *
1412  * IN iterationId - an iterator previously returned by
1413  * util_RPCStatsGetBegin.
1414  *
1415  * OUT stats - upon successful completion contains the next set of stats
1416  * from the server
1417  *
1418  * LOCKS
1419  *
1420  * No locks are obtained or released by this function
1421  *
1422  * RETURN CODES
1423  *
1424  * Returns != 0 upon successful completion.
1425  *
1426  */
1427
1428 int ADMINAPI
1429 util_RPCStatsGetNext(const void *iterationId, afs_RPCStats_p stats,
1430                      afs_status_p st)
1431 {
1432     int rc = 0;
1433     afs_status_t tst = 0;
1434     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1435
1436     if (iterationId == NULL) {
1437         tst = ADMITERATIONIDPNULL;
1438         goto fail_util_RPCStatsGetNext;
1439     }
1440
1441     if (stats == NULL) {
1442         tst = ADMUTILRPCSTATSNULL;
1443         goto fail_util_RPCStatsGetNext;
1444     }
1445
1446     rc = IteratorNext(iter, (void *)stats, &tst);
1447
1448   fail_util_RPCStatsGetNext:
1449
1450     if (st != NULL) {
1451         *st = tst;
1452     }
1453     return rc;
1454 }
1455
1456 /*
1457  * util_RPCStatsGetDone - finish using a stats iterator
1458  *
1459  * PARAMETERS
1460  *
1461  * IN iterationId - an iterator previously returned by
1462  * util_RPCStatsGetBegin.
1463  *
1464  * LOCKS
1465  *
1466  * No locks are obtained or released by this function
1467  *
1468  * RETURN CODES
1469  *
1470  * Returns != 0 upon successful completion.
1471  *
1472  */
1473
1474 int ADMINAPI
1475 util_RPCStatsGetDone(const void *iterationId, afs_status_p st)
1476 {
1477     int rc = 0;
1478     afs_status_t tst = 0;
1479     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1480
1481     if (iterationId == NULL) {
1482         tst = ADMITERATIONIDPNULL;
1483         goto fail_util_RPCStatsGetDone;
1484     }
1485
1486     rc = IteratorDone(iter, &tst);
1487
1488   fail_util_RPCStatsGetDone:
1489
1490     if (st != NULL) {
1491         *st = tst;
1492     }
1493     return rc;
1494 }
1495
1496 /*
1497  * util_RPCStatsStateGet - get the current state of rpc stat collection
1498  *
1499  * PARAMETERS
1500  *
1501  * IN conn - an rx connection to the process to be queried
1502  *
1503  * IN rpc - the function to call to make the actual rpc
1504  *
1505  * OUT state - the rpc stat collection state.
1506  *
1507  * LOCKS
1508  *
1509  * No locks are obtained or released by this function
1510  *
1511  * RETURN CODES
1512  *
1513  * Returns != 0 upon successful completion.
1514  *
1515  */
1516
1517 int ADMINAPI
1518 util_RPCStatsStateGet(struct rx_connection *conn, int (*rpc) (),
1519                       afs_RPCStatsState_p state, afs_status_p st)
1520 {
1521     int rc = 0;
1522     afs_status_t tst = 0;
1523
1524     if (conn == NULL) {
1525         tst = ADMRXCONNNULL;
1526         goto fail_util_RPCStatsStateGet;
1527     }
1528
1529     if (rpc == NULL) {
1530         tst = ADMRPCPTRNULL;
1531         goto fail_util_RPCStatsStateGet;
1532     }
1533
1534     if (state == NULL) {
1535         tst = ADMRPCSTATENULL;
1536         goto fail_util_RPCStatsStateGet;
1537     }
1538
1539     tst = (*rpc) (conn, state);
1540
1541     if (!tst) {
1542         rc = 1;
1543     }
1544
1545   fail_util_RPCStatsStateGet:
1546
1547     if (st != NULL) {
1548         *st = tst;
1549     }
1550     return rc;
1551 }
1552
1553 /*
1554  * util_RPCStatsStateEnable - enable rpc stat collection
1555  * to enabled
1556  *
1557  * PARAMETERS
1558  *
1559  * IN conn - an rx connection to the process to be modified
1560  *
1561  * IN rpc - the function to call to make the actual rpc
1562  *
1563  * LOCKS
1564  *
1565  * No locks are obtained or released by this function
1566  *
1567  * RETURN CODES
1568  *
1569  * Returns != 0 upon successful completion.
1570  *
1571  */
1572
1573 int ADMINAPI
1574 util_RPCStatsStateEnable(struct rx_connection *conn, int (*rpc) (),
1575                          afs_status_p st)
1576 {
1577     int rc = 0;
1578     afs_status_t tst = 0;
1579
1580     if (conn == NULL) {
1581         tst = ADMRXCONNNULL;
1582         goto fail_util_RPCStatsStateEnable;
1583     }
1584
1585     if (rpc == NULL) {
1586         tst = ADMRPCPTRNULL;
1587         goto fail_util_RPCStatsStateEnable;
1588     }
1589
1590     tst = (*rpc) (conn);
1591
1592     if (!tst) {
1593         rc = 1;
1594     }
1595
1596   fail_util_RPCStatsStateEnable:
1597
1598     if (st != NULL) {
1599         *st = tst;
1600     }
1601     return rc;
1602 }
1603
1604 /*
1605  * util_RPCStatsStateDisable - set the current state of rpc stat collection
1606  * to disabled
1607  *
1608  * PARAMETERS
1609  *
1610  * IN conn - an rx connection to the process to be modified
1611  *
1612  * IN rpc - the function to call to make the actual rpc
1613  *
1614  * LOCKS
1615  *
1616  * No locks are obtained or released by this function
1617  *
1618  * RETURN CODES
1619  *
1620  * Returns != 0 upon successful completion.
1621  *
1622  */
1623
1624 int ADMINAPI
1625 util_RPCStatsStateDisable(struct rx_connection *conn, int (*rpc) (),
1626                           afs_status_p st)
1627 {
1628     int rc = 0;
1629     afs_status_t tst = 0;
1630
1631     if (conn == NULL) {
1632         tst = ADMRXCONNNULL;
1633         goto fail_util_RPCStatsStateDisable;
1634     }
1635
1636     if (rpc == NULL) {
1637         tst = ADMRPCPTRNULL;
1638         goto fail_util_RPCStatsStateDisable;
1639     }
1640
1641     tst = (*rpc) (conn);
1642
1643     if (!tst) {
1644         rc = 1;
1645     }
1646
1647   fail_util_RPCStatsStateDisable:
1648
1649     if (st != NULL) {
1650         *st = tst;
1651     }
1652     return rc;
1653 }
1654
1655 /*
1656  * util_RPCStatsClear - clear some or all of the fields in the rpc stat
1657  * collection at a server
1658  *
1659  * PARAMETERS
1660  *
1661  * IN conn - an rx connection to the process to be modified
1662  *
1663  * IN rpc - the function to call to make the actual rpc
1664  *
1665  * IN flag - a flag containing the fields to be cleared
1666  *
1667  *
1668  * LOCKS
1669  *
1670  * No locks are obtained or released by this function
1671  *
1672  * RETURN CODES
1673  *
1674  * Returns != 0 upon successful completion.
1675  *
1676  */
1677
1678 int ADMINAPI
1679 util_RPCStatsClear(struct rx_connection *conn, int (*rpc) (),
1680                    afs_RPCStatsClearFlag_t flag, afs_status_p st)
1681 {
1682     int rc = 0;
1683     afs_status_t tst = 0;
1684
1685     if (conn == NULL) {
1686         tst = ADMRXCONNNULL;
1687         goto fail_util_RPCStatsClear;
1688     }
1689
1690     if (rpc == NULL) {
1691         tst = ADMRPCPTRNULL;
1692         goto fail_util_RPCStatsClear;
1693     }
1694
1695     tst = (*rpc) (conn, flag);
1696
1697     if (!tst) {
1698         rc = 1;
1699     }
1700
1701   fail_util_RPCStatsClear:
1702
1703     if (st != NULL) {
1704         *st = tst;
1705     }
1706     return rc;
1707 }
1708
1709 /*
1710  * util_RPCStatsVersionGet - get the current version of rpc stat collection
1711  *
1712  * PARAMETERS
1713  *
1714  * IN conn - an rx connection to the process to be modified
1715  *
1716  * OUT version - the version of rpc stat collection at the remote process
1717  *
1718  * LOCKS
1719  *
1720  * No locks are obtained or released by this function
1721  *
1722  * RETURN CODES
1723  *
1724  * Returns != 0 upon successful completion.
1725  *
1726  */
1727
1728 int ADMINAPI
1729 util_RPCStatsVersionGet(struct rx_connection *conn,
1730                         afs_RPCStatsVersion_p version, afs_status_p st)
1731 {
1732     int rc = 0;
1733     afs_status_t tst = 0;
1734
1735     if (conn == NULL) {
1736         tst = ADMRXCONNNULL;
1737         goto fail_util_RPCStatsVersionGet;
1738     }
1739
1740     if (version == NULL) {
1741         tst = ADMRPCVERSIONNULL;
1742         goto fail_util_RPCStatsVersionGet;
1743     }
1744
1745     tst = RXSTATS_QueryRPCStatsVersion(conn, version);
1746
1747     if (!tst) {
1748         rc = 1;
1749     }
1750
1751   fail_util_RPCStatsVersionGet:
1752
1753     if (st != NULL) {
1754         *st = tst;
1755     }
1756     return rc;
1757 }
1758
1759 /*
1760  * The iterator for listing CM server preferences
1761  */
1762
1763 typedef struct cm_srvr_pref_get {
1764     struct rx_connection *conn;
1765     afs_int32 index;
1766     afs_CMServerPref_t srvrPrefs[CACHED_ITEMS];
1767 } cm_srvr_pref_get_t, *cm_srvr_pref_get_p;
1768
1769 static int
1770 GetServerPrefsRPC(void *rpc_specific, int slot, int *last_item,
1771                   int *last_item_contains_data, afs_status_p st)
1772 {
1773     int rc = 0;
1774     afs_status_t tst = 0;
1775     cm_srvr_pref_get_p t = (cm_srvr_pref_get_p) rpc_specific;
1776
1777     /*
1778      * Get the next entry in the list of server preferences.
1779      */
1780     tst =
1781         RXAFSCB_GetServerPrefs(t->conn, t->index, &t->srvrPrefs[slot].ipAddr,
1782                                &t->srvrPrefs[slot].ipRank);
1783     if (tst) {
1784         goto fail_GetServerPrefsRPC;
1785     }
1786
1787     /*
1788      * See if we've processed all the entries
1789      */
1790     if (t->srvrPrefs[slot].ipAddr == 0xffffffff) {
1791         *last_item = 1;
1792         *last_item_contains_data = 0;
1793     } else {
1794         t->index += 1;
1795     }
1796     rc = 1;
1797
1798   fail_GetServerPrefsRPC:
1799
1800     if (st != NULL) {
1801         *st = tst;
1802     }
1803     return rc;
1804 }
1805
1806 static int
1807 GetServerPrefsFromCache(void *rpc_specific, int slot, void *dest,
1808                         afs_status_p st)
1809 {
1810     int rc = 0;
1811     afs_status_t tst = 0;
1812     cm_srvr_pref_get_p prefs = (cm_srvr_pref_get_p) rpc_specific;
1813
1814     memcpy(dest, (const void *)&prefs->srvrPrefs[slot],
1815            sizeof(afs_CMServerPref_t));
1816
1817     rc = 1;
1818     if (st != NULL) {
1819         *st = tst;
1820     }
1821     return rc;
1822 }
1823
1824 /*
1825  * util_CMGetServerPrefsBegin - Begin listing cache manager server preferences
1826  *
1827  * PARAMETERS
1828  *
1829  * IN conn - an rx connection to the process to be queried
1830  *
1831  * OUT iterationIdP - an iteration id that can be passed to
1832  * util_CMGetServerPrefsNext to get the next server preference
1833  *
1834  * LOCKS
1835  *
1836  * No locks are obtained or released by this function
1837  *
1838  * RETURN CODES
1839  *
1840  * Returns != 0 upon successful completion.
1841  *
1842  */
1843
1844 int ADMINAPI
1845 util_CMGetServerPrefsBegin(struct rx_connection *conn, void **iterationIdP,
1846                            afs_status_p st)
1847 {
1848     int rc = 0;
1849     afs_status_t tst = 0;
1850     afs_admin_iterator_p iter;
1851     cm_srvr_pref_get_p pref;
1852
1853     if (conn == NULL) {
1854         tst = ADMRXCONNNULL;
1855         goto fail_util_CMGetServerPrefsBegin;
1856     }
1857
1858     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1859     if (iter == NULL) {
1860         tst = ADMNOMEM;
1861         goto fail_util_CMGetServerPrefsBegin;
1862     }
1863
1864     pref = (cm_srvr_pref_get_p) malloc(sizeof(cm_srvr_pref_get_t));
1865     if (pref == NULL) {
1866         free(iter);
1867         tst = ADMNOMEM;
1868         goto fail_util_CMGetServerPrefsBegin;
1869     }
1870
1871     pref->conn = conn;
1872     pref->index = 0;
1873     if (!IteratorInit
1874         (iter, (void *)pref, GetServerPrefsRPC, GetServerPrefsFromCache, NULL,
1875          NULL, &tst)) {
1876         free(iter);
1877         free(pref);
1878         goto fail_util_CMGetServerPrefsBegin;
1879     }
1880     *iterationIdP = (void *)iter;
1881     rc = 1;
1882
1883   fail_util_CMGetServerPrefsBegin:
1884
1885     if (st != NULL) {
1886         *st = tst;
1887     }
1888     return rc;
1889 }
1890
1891 /*
1892  * util_CMGetServerPrefsNext - Get next entry in cache manager server
1893  *                             preferences
1894  *
1895  * PARAMETERS
1896  *
1897  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
1898  *
1899  * OUT prefs - Next entry in cache manager server preferences.
1900  *
1901  * LOCKS
1902  *
1903  * No locks are obtained or released by this function
1904  *
1905  * RETURN CODES
1906  *
1907  * Returns != 0 upon successful completion.
1908  *
1909  */
1910
1911 int ADMINAPI
1912 util_CMGetServerPrefsNext(const void *iterationId, afs_CMServerPref_p prefs,
1913                           afs_status_p st)
1914 {
1915     int rc = 0;
1916     afs_status_t tst = 0;
1917     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1918
1919     if (iterationId == NULL) {
1920         tst = ADMITERATIONIDPNULL;
1921         goto fail_util_CMGetServerPrefsNext;
1922     }
1923
1924     rc = IteratorNext(iter, (void *)prefs, &tst);
1925
1926   fail_util_CMGetServerPrefsNext:
1927
1928     if (st != NULL) {
1929         *st = tst;
1930     }
1931     return rc;
1932 }
1933
1934 /*
1935  * util_CMGetServerPrefsDone - Finish listing cache manager server
1936  *                             preferences
1937  *
1938  * PARAMETERS
1939  *
1940  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
1941  *
1942  * LOCKS
1943  *
1944  * No locks are obtained or released by this function
1945  *
1946  * RETURN CODES
1947  *
1948  * Returns != 0 upon successful completion.
1949  *
1950  */
1951
1952 int ADMINAPI
1953 util_CMGetServerPrefsDone(const void *iterationId, afs_status_p st)
1954 {
1955     int rc = 0;
1956     afs_status_t tst = 0;
1957     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1958
1959     if (iterationId == NULL) {
1960         tst = ADMITERATIONIDPNULL;
1961         goto fail_util_CMGetServerPrefsDone;
1962     }
1963
1964     rc = IteratorDone(iter, &tst);
1965
1966
1967   fail_util_CMGetServerPrefsDone:
1968
1969     if (st != NULL) {
1970         *st = tst;
1971     }
1972     return rc;
1973 }
1974
1975 /*
1976  * The iterator for listing CM CellServDB
1977  */
1978
1979 typedef struct cm_list_cell_get {
1980     struct rx_connection *conn;
1981     afs_int32 index;
1982     afs_CMListCell_t cell[CACHED_ITEMS];
1983 } cm_list_cell_get_t, *cm_list_cell_get_p;
1984
1985 static int
1986 ListCellsRPC(void *rpc_specific, int slot, int *last_item,
1987              int *last_item_contains_data, afs_status_p st)
1988 {
1989     int rc = 0;
1990     afs_status_t tst = 0;
1991     cm_list_cell_get_p t = (cm_list_cell_get_p) rpc_specific;
1992     char *name;
1993
1994     /*
1995      * Get the next entry in the CellServDB.
1996      */
1997     name = t->cell[slot].cellname;
1998     tst =
1999         RXAFSCB_GetCellServDB(t->conn, t->index, &name,
2000                               t->cell[slot].serverAddr);
2001     if (tst) {
2002         goto fail_ListCellsRPC;
2003     }
2004     strcpy(t->cell[slot].cellname, name);
2005
2006     /*
2007      * See if we've processed all the entries
2008      */
2009     if (strlen(t->cell[slot].cellname) == 0) {
2010         *last_item = 1;
2011         *last_item_contains_data = 0;
2012     } else {
2013         t->index += 1;
2014     }
2015     rc = 1;
2016
2017   fail_ListCellsRPC:
2018
2019     if (st != NULL) {
2020         *st = tst;
2021     }
2022     return rc;
2023 }
2024
2025 static int
2026 ListCellsFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
2027 {
2028     int rc = 0;
2029     afs_status_t tst = 0;
2030     cm_list_cell_get_p cell = (cm_list_cell_get_p) rpc_specific;
2031
2032     memcpy(dest, (const void *)&cell->cell[slot], sizeof(afs_CMListCell_t));
2033
2034     rc = 1;
2035     if (st != NULL) {
2036         *st = tst;
2037     }
2038     return rc;
2039 }
2040
2041 /*
2042  * util_CMListCellsBegin - Begin listing cache manager CellServDB
2043  *
2044  * PARAMETERS
2045  *
2046  * IN conn - an rx connection to the process to be queried
2047  *
2048  * OUT iterationIdP - an iteration id that can be passed to
2049  * util_CMListCellsNext to get the next cell
2050  *
2051  * LOCKS
2052  *
2053  * No locks are obtained or released by this function
2054  *
2055  * RETURN CODES
2056  *
2057  * Returns != 0 upon successful completion.
2058  *
2059  */
2060
2061 int ADMINAPI
2062 util_CMListCellsBegin(struct rx_connection *conn, void **iterationIdP,
2063                       afs_status_p st)
2064 {
2065     int rc = 0;
2066     afs_status_t tst = 0;
2067     afs_admin_iterator_p iter;
2068     cm_list_cell_get_p cell;
2069
2070     if (conn == NULL) {
2071         tst = ADMRXCONNNULL;
2072         goto fail_util_CMListCellsBegin;
2073     }
2074
2075     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2076     if (iter == NULL) {
2077         tst = ADMNOMEM;
2078         goto fail_util_CMListCellsBegin;
2079     }
2080
2081     cell = (cm_list_cell_get_p) malloc(sizeof(cm_list_cell_get_t));
2082     if (cell == NULL) {
2083         free(iter);
2084         tst = ADMNOMEM;
2085         goto fail_util_CMListCellsBegin;
2086     }
2087
2088     cell->conn = conn;
2089     cell->index = 0;
2090     if (!IteratorInit
2091         (iter, (void *)cell, ListCellsRPC, ListCellsFromCache, NULL, NULL,
2092          &tst)) {
2093         free(iter);
2094         free(cell);
2095         goto fail_util_CMListCellsBegin;
2096     }
2097     *iterationIdP = (void *)iter;
2098     rc = 1;
2099
2100   fail_util_CMListCellsBegin:
2101
2102     if (st != NULL) {
2103         *st = tst;
2104     }
2105     return rc;
2106 }
2107
2108 /*
2109  * util_CMListCellsNext - Get next entry in cache manager cells
2110  *
2111  * PARAMETERS
2112  *
2113  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
2114  *
2115  * OUT cell - Next entry in cache manager cells.
2116  *
2117  * LOCKS
2118  *
2119  * No locks are obtained or released by this function
2120  *
2121  * RETURN CODES
2122  *
2123  * Returns != 0 upon successful completion.
2124  *
2125  */
2126
2127 int ADMINAPI
2128 util_CMListCellsNext(const void *iterationId, afs_CMListCell_p cell,
2129                      afs_status_p st)
2130 {
2131     int rc = 0;
2132     afs_status_t tst = 0;
2133     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2134
2135     if (iterationId == NULL) {
2136         tst = ADMITERATIONIDPNULL;
2137         goto fail_util_CMListCellsNext;
2138     }
2139
2140     rc = IteratorNext(iter, (void *)cell, &tst);
2141
2142   fail_util_CMListCellsNext:
2143
2144     if (st != NULL) {
2145         *st = tst;
2146     }
2147     return rc;
2148 }
2149
2150 /*
2151  * util_CMListCellsDone - Finish listing cache manager cells
2152  *
2153  * PARAMETERS
2154  *
2155  * IN iterationId - Iteration id created by util_CMGetServerPrefsBegin.
2156  *
2157  * LOCKS
2158  *
2159  * No locks are obtained or released by this function
2160  *
2161  * RETURN CODES
2162  *
2163  * Returns != 0 upon successful completion.
2164  *
2165  */
2166
2167 int ADMINAPI
2168 util_CMListCellsDone(const void *iterationId, afs_status_p st)
2169 {
2170     int rc = 0;
2171     afs_status_t tst = 0;
2172     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2173
2174     if (iterationId == NULL) {
2175         tst = ADMITERATIONIDPNULL;
2176         goto fail_util_CMListCellsDone;
2177     }
2178
2179     rc = IteratorDone(iter, &tst);
2180
2181
2182   fail_util_CMListCellsDone:
2183
2184     if (st != NULL) {
2185         *st = tst;
2186     }
2187     return rc;
2188 }
2189
2190 /*
2191  * util_CMLocalCell - Get the name of the cache manager's local cell.
2192  *
2193  * PARAMETERS
2194  *
2195  * IN conn - an rx connection to the process to be queried
2196  *
2197  * OUT cellName - the name of the cache manager's local cell.
2198  *
2199  * LOCKS
2200  *
2201  * No locks are obtained or released by this function
2202  *
2203  * RETURN CODES
2204  *
2205  * Returns != 0 upon successful completion.
2206  *
2207  */
2208
2209 int ADMINAPI
2210 util_CMLocalCell(struct rx_connection *conn, afs_CMCellName_p cellName,
2211                  afs_status_p st)
2212 {
2213     int rc = 0;
2214     afs_status_t tst = 0;
2215     afs_CMCellName_p name;
2216
2217     if (conn == NULL) {
2218         tst = ADMRXCONNNULL;
2219         goto fail_util_CMLocalCell;
2220     }
2221
2222     if (cellName == NULL) {
2223         tst = ADMCLIENTCMCELLNAMENULL;
2224         goto fail_util_CMLocalCell;
2225     }
2226
2227     name = cellName;
2228     tst = RXAFSCB_GetLocalCell(conn, &name);
2229
2230     if (!tst) {
2231         rc = 1;
2232     }
2233
2234   fail_util_CMLocalCell:
2235
2236     if (st != NULL) {
2237         *st = tst;
2238     }
2239     return rc;
2240 }
2241
2242 static void
2243 UnmarshallCMClientConfig(afs_uint32 serverVersion, afs_uint32 * ptr,
2244                          afs_ClientConfigUnion_p config)
2245 {
2246     /*
2247      * We currently only support version 1.
2248      */
2249     config->config_v1.nChunkFiles = *(ptr++);
2250     config->config_v1.nStatCaches = *(ptr++);
2251     config->config_v1.nDataCaches = *(ptr++);
2252     config->config_v1.nVolumeCaches = *(ptr++);
2253     config->config_v1.firstChunkSize = *(ptr++);
2254     config->config_v1.otherChunkSize = *(ptr++);
2255     config->config_v1.cacheSize = *(ptr++);
2256     config->config_v1.setTime = *(ptr++);
2257     config->config_v1.memCache = *(ptr++);
2258 }
2259
2260 /*
2261  * util_CMClientConfig - Get the cache manager's configuration parameters.
2262  *
2263  * PARAMETERS
2264  *
2265  * IN conn - an rx connection to the process to be queried
2266  *
2267  * OUT config - the cache manager's configuration parameters.
2268  *
2269  * LOCKS
2270  *
2271  * No locks are obtained or released by this function
2272  *
2273  * RETURN CODES
2274  *
2275  * Returns != 0 upon successful completion.
2276  *
2277  */
2278
2279 int ADMINAPI
2280 util_CMClientConfig(struct rx_connection *conn, afs_ClientConfig_p config,
2281                     afs_status_p st)
2282 {
2283     int rc = 0;
2284     afs_status_t tst = 0;
2285     afs_int32 allocbytes;
2286     struct cacheConfig tconfig;
2287
2288     if (conn == NULL) {
2289         tst = ADMRXCONNNULL;
2290         goto fail_util_CMClientConfig;
2291     }
2292
2293     if (config == NULL) {
2294         tst = ADMCLIENTCMCELLNAMENULL;
2295         goto fail_util_CMClientConfig;
2296     }
2297
2298     config->clientVersion = AFS_CLIENT_RETRIEVAL_VERSION;
2299     tconfig.cacheConfig_val = NULL;
2300     tconfig.cacheConfig_len = 0;
2301     tst =
2302         RXAFSCB_GetCacheConfig(conn, config->clientVersion,
2303                                &config->serverVersion, &allocbytes, &tconfig);
2304
2305     if (tst) {
2306         goto fail_util_CMClientConfig;
2307     }
2308
2309     UnmarshallCMClientConfig(config->serverVersion, tconfig.cacheConfig_val,
2310                              &config->c);
2311     rc = 1;
2312     free(tconfig.cacheConfig_val);
2313
2314   fail_util_CMClientConfig:
2315
2316     if (st != NULL) {
2317         *st = tst;
2318     }
2319     return rc;
2320 }
2321
2322 /*
2323  * util_RXDebugVersion - Get the rxdebug version string.
2324  *
2325  * PARAMETERS
2326  *
2327  * IN handle - an rxdebug handle for the process to be queried.
2328  *
2329  * OUT version - the rxdebug version string.
2330  *
2331  * LOCKS
2332  *
2333  * No locks are obtained or released by this function
2334  *
2335  * RETURN CODES
2336  *
2337  * Returns != 0 upon successful completion.
2338  *
2339  */
2340
2341 int ADMINAPI
2342 util_RXDebugVersion(rxdebugHandle_p handle, rxdebugVersion_p version,
2343                     afs_status_p st)
2344 {
2345     int rc = 0;
2346     afs_status_t tst = 0;
2347     int code;
2348
2349     if (handle == NULL) {
2350         tst = ADMRXDEBUGHANDLENULL;
2351         goto fail_util_RXDebugVersion;
2352     }
2353
2354     if (version == NULL) {
2355         tst = ADMRXDEBUGVERSIONNULL;
2356         goto fail_util_RXDebugVersion;
2357     }
2358
2359     code =
2360         rx_GetServerVersion(handle->sock, handle->ipAddr, handle->udpPort,
2361                             UTIL_MAX_RXDEBUG_VERSION_LEN, version);
2362     if (code < 0) {
2363         tst = ADMCLIENTRXDEBUGTIMEOUT;
2364         goto fail_util_RXDebugVersion;
2365     }
2366
2367     rc = 1;
2368
2369   fail_util_RXDebugVersion:
2370
2371     if (st != NULL) {
2372         *st = tst;
2373     }
2374     return rc;
2375 }
2376
2377 /*
2378  * util_RXDebugSupportedStats - Get the rxdebug statistics supported by
2379  *                              the process.
2380  *
2381  * PARAMETERS
2382  *
2383  * IN handle - an rxdebug handle for the process to be queried.
2384  *
2385  * OUT supportedStats - bit mask with supported rxstats.
2386  *
2387  * LOCKS
2388  *
2389  * No locks are obtained or released by this function
2390  *
2391  * RETURN CODES
2392  *
2393  * Returns != 0 upon successful completion.
2394  *
2395  */
2396
2397 int ADMINAPI
2398 util_RXDebugSupportedStats(rxdebugHandle_p handle,
2399                            afs_uint32 * supportedStats, afs_status_p st)
2400 {
2401     int rc = 0;
2402     afs_status_t tst = 0;
2403     struct rx_debugStats tstats;
2404
2405     if (handle == NULL) {
2406         tst = ADMRXDEBUGHANDLENULL;
2407         goto fail_util_RXDebugSupportedStats;
2408     }
2409
2410     if (supportedStats == NULL) {
2411         tst = ADMRXDEBUGSTATSNULL;
2412         goto fail_util_RXDebugSupportedStats;
2413     }
2414
2415     if (handle->firstFlag) {
2416         rc = util_RXDebugBasicStats(handle, &tstats, &tst);
2417         if (!rc) {
2418             goto fail_util_RXDebugSupportedStats;
2419         }
2420     }
2421
2422     *supportedStats = handle->supportedStats;
2423     rc = 1;
2424
2425   fail_util_RXDebugSupportedStats:
2426
2427     if (st != NULL) {
2428         *st = tst;
2429     }
2430     return rc;
2431 }
2432
2433
2434 /*
2435  * util_RXDebugBasicStats - Get the basic rxdebug statistics for the process.
2436  *
2437  * PARAMETERS
2438  *
2439  * IN handle - an rxdebug handle for the process to be queried.
2440  *
2441  * OUT stats - Basic rxdebug statistics for the process.
2442  *
2443  * LOCKS
2444  *
2445  * No locks are obtained or released by this function
2446  *
2447  * RETURN CODES
2448  *
2449  * Returns != 0 upon successful completion.
2450  *
2451  */
2452
2453 int ADMINAPI
2454 util_RXDebugBasicStats(rxdebugHandle_p handle, struct rx_debugStats *stats,
2455                        afs_status_p st)
2456 {
2457     int rc = 0;
2458     afs_status_t tst = 0;
2459     int code;
2460
2461     if (handle == NULL) {
2462         tst = ADMRXDEBUGHANDLENULL;
2463         goto fail_util_RXDebugBasicStats;
2464     }
2465
2466     if (stats == NULL) {
2467         tst = ADMRXDEBUGSTATSNULL;
2468         goto fail_util_RXDebugBasicStats;
2469     }
2470
2471     code =
2472         rx_GetServerDebug(handle->sock, handle->ipAddr, handle->udpPort,
2473                           stats, &handle->supportedStats);
2474     if (code < 0) {
2475         tst = ADMCLIENTRXDEBUGTIMEOUT;
2476         goto fail_util_RXDebugBasicStats;
2477     }
2478
2479     handle->firstFlag = 0;
2480     rc = 1;
2481
2482   fail_util_RXDebugBasicStats:
2483
2484     if (st != NULL) {
2485         *st = tst;
2486     }
2487     return rc;
2488 }
2489
2490
2491 /*
2492  * util_RXDebugRxStats - Get the detailed rxdebug statistics for the process.
2493  *
2494  * PARAMETERS
2495  *
2496  * IN handle - an rxdebug handle for the process to be queried.
2497  *
2498  * OUT stats - Detailed rxdebug statistics for the process.
2499  *
2500  * LOCKS
2501  *
2502  * No locks are obtained or released by this function
2503  *
2504  * RETURN CODES
2505  *
2506  * Returns != 0 upon successful completion.
2507  *
2508  */
2509
2510 int ADMINAPI
2511 util_RXDebugRxStats(rxdebugHandle_p handle, struct rx_stats *stats,
2512                     afs_uint32 * supportedValues, afs_status_p st)
2513 {
2514     int rc = 0;
2515     int trc;
2516     afs_status_t tst = 0;
2517     int code;
2518     afs_uint32 tsupported;
2519
2520     if (handle == NULL) {
2521         tst = ADMRXDEBUGHANDLENULL;
2522         goto fail_util_RXDebugRxStats;
2523     }
2524
2525     if (supportedValues == NULL) {
2526         tst = ADMRXDEBUGSTATSNULL;
2527         goto fail_util_RXDebugRxStats;
2528     }
2529
2530     if (stats == NULL) {
2531         tst = ADMRXDEBUGSTATSNULL;
2532         goto fail_util_RXDebugRxStats;
2533     }
2534
2535     if (handle->firstFlag) {
2536         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
2537         if (!trc) {
2538             rc = trc;
2539             goto fail_util_RXDebugRxStats;
2540         }
2541     }
2542
2543     if (!(handle->supportedStats & RX_SERVER_DEBUG_RX_STATS)) {
2544         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
2545         goto fail_util_RXDebugRxStats;
2546     }
2547
2548     code =
2549         rx_GetServerStats(handle->sock, handle->ipAddr, handle->udpPort,
2550                           stats, &handle->supportedStats);
2551     if (code < 0) {
2552         tst = ADMCLIENTRXDEBUGTIMEOUT;
2553         goto fail_util_RXDebugRxStats;
2554     }
2555
2556     rc = 1;
2557
2558   fail_util_RXDebugRxStats:
2559
2560     if (st != NULL) {
2561         *st = tst;
2562     }
2563     return rc;
2564 }
2565
2566 /*
2567  * The iterator for listing RXDebug connections
2568  */
2569
2570 typedef struct rxdebug_conn_item {
2571     struct rx_debugConn conn;
2572     afs_uint32 supportedValues;
2573 } rxdebug_conn_item_t, *rxdebug_conn_item_p;
2574
2575 typedef struct rxdebug_conn_get {
2576     int allconns;
2577     rxdebugHandle_p handle;
2578     afs_int32 index;
2579     rxdebug_conn_item_t items[CACHED_ITEMS];
2580 } rxdebug_conn_get_t, *rxdebug_conn_get_p;
2581
2582 static int
2583 RXDebugConnsFromServer(void *rpc_specific, int slot, int *last_item,
2584                        int *last_item_contains_data, afs_status_p st)
2585 {
2586     int rc = 0;
2587     int code;
2588     afs_status_t tst = 0;
2589     rxdebug_conn_get_p t = (rxdebug_conn_get_p) rpc_specific;
2590
2591     /*
2592      * Get the next entry the list of connections
2593      */
2594     code =
2595         rx_GetServerConnections(t->handle->sock, t->handle->ipAddr,
2596                                 t->handle->udpPort, &t->index, t->allconns,
2597                                 t->handle->supportedStats,
2598                                 &t->items[slot].conn,
2599                                 &t->items[slot].supportedValues);
2600     if (code < 0) {
2601         tst = ADMCLIENTRXDEBUGTIMEOUT;
2602         goto fail_ListCellsRPC;
2603     }
2604
2605     /*
2606      * See if we've processed all the entries
2607      */
2608     if (t->items[slot].conn.cid == 0xffffffff) {
2609         *last_item = 1;
2610         *last_item_contains_data = 0;
2611     }
2612     rc = 1;
2613
2614   fail_ListCellsRPC:
2615
2616     if (st != NULL) {
2617         *st = tst;
2618     }
2619     return rc;
2620 }
2621
2622 static int
2623 RXDebugConnsFromCache(void *rpc_specific, int slot, void *dest,
2624                       afs_status_p st)
2625 {
2626     int rc = 0;
2627     afs_status_t tst = 0;
2628     rxdebug_conn_get_p t = (rxdebug_conn_get_p) rpc_specific;
2629
2630     memcpy(dest, (const void *)&t->items[slot], sizeof(rxdebug_conn_item_t));
2631
2632     rc = 1;
2633     if (st != NULL) {
2634         *st = tst;
2635     }
2636     return rc;
2637 }
2638
2639 /*
2640  * util_RXDebugConnectionsBegin - Begin listing rxdebug connection information
2641  *                                for a process.
2642  *
2643  * PARAMETERS
2644  *
2645  * IN handle - an rxdebug handle for the process to be queried
2646  *
2647  * IN allcons - non-zero to list all connections. If zero, only
2648  *              "interesting" connections will be listed.
2649  *
2650  * OUT iterationIdP - an iteration id that can be passed to
2651  *                    util_RXDebugConnectionsNext.
2652  *
2653  * LOCKS
2654  *
2655  * No locks are obtained or released by this function
2656  *
2657  * RETURN CODES
2658  *
2659  * Returns != 0 upon successful completion.
2660  *
2661  */
2662
2663 int ADMINAPI
2664 util_RXDebugConnectionsBegin(rxdebugHandle_p handle, int allconns,
2665                              void **iterationIdP, afs_status_p st)
2666 {
2667     int rc = 0;
2668     int trc;
2669     afs_uint32 tsupported;
2670     afs_status_t tst = 0;
2671     afs_admin_iterator_p iter;
2672     rxdebug_conn_get_p t;
2673
2674     if (handle == NULL) {
2675         tst = ADMRXDEBUGHANDLENULL;
2676         goto fail_util_RXDebugConnectionsBegin;
2677     }
2678
2679     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2680     if (iter == NULL) {
2681         tst = ADMNOMEM;
2682         goto fail_util_RXDebugConnectionsBegin;
2683     }
2684
2685     if (handle->firstFlag) {
2686         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
2687         if (!trc) {
2688             rc = trc;
2689             goto fail_util_RXDebugConnectionsBegin;
2690         }
2691     }
2692
2693     if (allconns && !(handle->supportedStats & RX_SERVER_DEBUG_ALL_CONN)) {
2694         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
2695         goto fail_util_RXDebugConnectionsBegin;
2696     }
2697
2698     t = (rxdebug_conn_get_p) malloc(sizeof(rxdebug_conn_get_t));
2699     if (t == NULL) {
2700         free(iter);
2701         tst = ADMNOMEM;
2702         goto fail_util_RXDebugConnectionsBegin;
2703     }
2704
2705     t->allconns = allconns;
2706     t->handle = handle;
2707     t->index = 0;
2708     if (!IteratorInit
2709         (iter, (void *)t, RXDebugConnsFromServer, RXDebugConnsFromCache, NULL,
2710          NULL, &tst)) {
2711         goto fail_util_RXDebugConnectionsBegin;
2712     }
2713     *iterationIdP = (void *)iter;
2714     rc = 1;
2715
2716   fail_util_RXDebugConnectionsBegin:
2717
2718     if (st != NULL) {
2719         *st = tst;
2720     }
2721     return rc;
2722 }
2723
2724
2725 /*
2726  * util_RXDebugConnectionsNext - Get rxdebug information for the next
2727  *                               connection.
2728  *
2729  * PARAMETERS
2730  *
2731  * IN iterationId - Iteration id created by util_RXDebugConnectionsNext.
2732  *
2733  * OUT conn - Rxdebug information for the next connection.
2734  *
2735  * OUT supportedValues - Bit mask of supported rxdebug values.
2736  *
2737  * LOCKS
2738  *
2739  * No locks are obtained or released by this function
2740  *
2741  * RETURN CODES
2742  *
2743  * Returns != 0 upon successful completion.
2744  *
2745  */
2746
2747 int ADMINAPI
2748 util_RXDebugConnectionsNext(const void *iterationId,
2749                             struct rx_debugConn *conn,
2750                             afs_uint32 * supportedValues, afs_status_p st)
2751 {
2752     int rc = 0;
2753     afs_status_t tst = 0;
2754     rxdebug_conn_item_t item;
2755     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2756
2757     if (iterationId == NULL) {
2758         tst = ADMITERATIONIDPNULL;
2759         goto fail_util_RXDebugConnectionsNext;
2760     }
2761
2762     if (conn == NULL) {
2763         tst = ADMRXDEBUGHANDLENULL;
2764         goto fail_util_RXDebugConnectionsNext;
2765     }
2766
2767     if (supportedValues == NULL) {
2768         tst = ADMRXDEBUGHANDLENULL;
2769         goto fail_util_RXDebugConnectionsNext;
2770     }
2771
2772     rc = IteratorNext(iter, (void *)&item, &tst);
2773     if (!rc) {
2774         goto fail_util_RXDebugConnectionsNext;
2775     }
2776
2777     *conn = item.conn;
2778     *supportedValues = item.supportedValues;
2779
2780   fail_util_RXDebugConnectionsNext:
2781
2782     if (st != NULL) {
2783         *st = tst;
2784     }
2785     return rc;
2786 }
2787
2788
2789 /*
2790  * util_RXDebugConnectionsDone - Finish listing rxdebug connection information.
2791  *
2792  * PARAMETERS
2793  *
2794  * IN iterationId - Iteration id created by util_RXDebugConnectionsBegin.
2795  *
2796  * LOCKS
2797  *
2798  * No locks are obtained or released by this function
2799  *
2800  * RETURN CODES
2801  *
2802  * Returns != 0 upon successful completion.
2803  *
2804  */
2805
2806 int ADMINAPI
2807 util_RXDebugConnectionsDone(const void *iterationId, afs_status_p st)
2808 {
2809     int rc = 0;
2810     afs_status_t tst = 0;
2811     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2812
2813     /*
2814      * Validate parameters
2815      */
2816
2817     if (iter == NULL) {
2818         tst = ADMITERATORNULL;
2819         goto fail_util_RXDebugConnectionsDone;
2820     }
2821
2822     rc = IteratorDone(iter, &tst);
2823
2824   fail_util_RXDebugConnectionsDone:
2825
2826     if (st != NULL) {
2827         *st = tst;
2828     }
2829     return rc;
2830
2831 }
2832
2833 /*
2834  * The iterator for listing RXDebug peer
2835  */
2836
2837 typedef struct rxdebug_peer_item {
2838     struct rx_debugPeer peer;
2839     afs_uint32 supportedValues;
2840 } rxdebug_peer_item_t, *rxdebug_peer_item_p;
2841
2842 typedef struct rxdebug_peer_get {
2843     rxdebugHandle_p handle;
2844     afs_int32 index;
2845     rxdebug_peer_item_t items[CACHED_ITEMS];
2846 } rxdebug_peer_get_t, *rxdebug_peer_get_p;
2847
2848 static int
2849 RXDebugPeersFromServer(void *rpc_specific, int slot, int *last_item,
2850                        int *last_item_contains_data, afs_status_p st)
2851 {
2852     int rc = 0;
2853     int code;
2854     afs_status_t tst = 0;
2855     rxdebug_peer_get_p t = (rxdebug_peer_get_p) rpc_specific;
2856
2857     /*
2858      * Get the next entry the list of peers
2859      */
2860     code =
2861         rx_GetServerPeers(t->handle->sock, t->handle->ipAddr,
2862                           t->handle->udpPort, &t->index,
2863                           t->handle->supportedStats, &t->items[slot].peer,
2864                           &t->items[slot].supportedValues);
2865     if (code < 0) {
2866         tst = ADMCLIENTRXDEBUGTIMEOUT;
2867         goto fail_ListCellsRPC;
2868     }
2869
2870     /*
2871      * See if we've processed all the entries
2872      */
2873     if (t->items[slot].peer.host == 0xffffffff) {
2874         *last_item = 1;
2875         *last_item_contains_data = 0;
2876     }
2877     rc = 1;
2878
2879   fail_ListCellsRPC:
2880
2881     if (st != NULL) {
2882         *st = tst;
2883     }
2884     return rc;
2885 }
2886
2887 static int
2888 RXDebugPeersFromCache(void *rpc_specific, int slot, void *dest,
2889                       afs_status_p st)
2890 {
2891     int rc = 0;
2892     afs_status_t tst = 0;
2893     rxdebug_peer_get_p t = (rxdebug_peer_get_p) rpc_specific;
2894
2895     memcpy(dest, (const void *)&t->items[slot], sizeof(rxdebug_peer_item_t));
2896
2897     rc = 1;
2898     if (st != NULL) {
2899         *st = tst;
2900     }
2901     return rc;
2902 }
2903
2904
2905 /*
2906  * util_RXDebugPeersBegin - Begin listing rxdebug peer information for
2907  *                          a process.
2908  *
2909  * PARAMETERS
2910  *
2911  * IN handle - an rxdebug handle for the process to be queried
2912  *
2913  * OUT iterationIdP - an iteration id that can be passed to
2914  *                    util_RXDebugPeersNext.
2915  *
2916  * LOCKS
2917  *
2918  * No locks are obtained or released by this function
2919  *
2920  * RETURN CODES
2921  *
2922  * Returns != 0 upon successful completion.
2923  *
2924  */
2925
2926 int ADMINAPI
2927 util_RXDebugPeersBegin(rxdebugHandle_p handle, void **iterationIdP,
2928                        afs_status_p st)
2929 {
2930     int rc = 0;
2931     int trc;
2932     afs_uint32 tsupported;
2933     afs_status_t tst = 0;
2934     afs_admin_iterator_p iter;
2935     rxdebug_peer_get_p t;
2936
2937     if (handle == NULL) {
2938         tst = ADMRXDEBUGHANDLENULL;
2939         goto fail_util_RXDebugPeersBegin;
2940     }
2941
2942     iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2943     if (iter == NULL) {
2944         tst = ADMNOMEM;
2945         goto fail_util_RXDebugPeersBegin;
2946     }
2947
2948     if (handle->firstFlag) {
2949         trc = util_RXDebugSupportedStats(handle, &tsupported, &tst);
2950         if (!trc) {
2951             rc = trc;
2952             goto fail_util_RXDebugPeersBegin;
2953         }
2954     }
2955
2956     if (!(handle->supportedStats & RX_SERVER_DEBUG_ALL_PEER)) {
2957         tst = ADMCLIENTRXDEBUGNOTSUPPORTED;
2958         goto fail_util_RXDebugPeersBegin;
2959     }
2960
2961     t = (rxdebug_peer_get_p) malloc(sizeof(rxdebug_peer_get_t));
2962     if (t == NULL) {
2963         free(iter);
2964         tst = ADMNOMEM;
2965         goto fail_util_RXDebugPeersBegin;
2966     }
2967
2968     t->handle = handle;
2969     t->index = 0;
2970     if (!IteratorInit
2971         (iter, (void *)t, RXDebugPeersFromServer, RXDebugPeersFromCache, NULL,
2972          NULL, &tst)) {
2973         goto fail_util_RXDebugPeersBegin;
2974     }
2975     *iterationIdP = (void *)iter;
2976     rc = 1;
2977
2978   fail_util_RXDebugPeersBegin:
2979
2980     if (st != NULL) {
2981         *st = tst;
2982     }
2983     return rc;
2984 }
2985
2986 /*
2987  * util_RXDebugPeersNext - Get rxdebug information for the next peer.
2988  *
2989  * PARAMETERS
2990  *
2991  * IN iterationId - Iteration id created by util_RXDebugPeersBegin.
2992  *
2993  * OUT peer - Rxdebug information for the next peer.
2994  *
2995  * OUT supportedValues - Bit mask of supported rxdebug values.
2996  *
2997  * LOCKS
2998  *
2999  * No locks are obtained or released by this function
3000  *
3001  * RETURN CODES
3002  *
3003  * Returns != 0 upon successful completion.
3004  *
3005  */
3006 int ADMINAPI
3007 util_RXDebugPeersNext(const void *iterationId, struct rx_debugPeer *peer,
3008                       afs_uint32 * supportedValues, afs_status_p st)
3009 {
3010     int rc = 0;
3011     afs_status_t tst = 0;
3012     rxdebug_peer_item_t item;
3013     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3014
3015     if (iterationId == NULL) {
3016         tst = ADMITERATIONIDPNULL;
3017         goto fail_util_RXDebugPeersNext;
3018     }
3019
3020     if (peer == NULL) {
3021         tst = ADMRXDEBUGHANDLENULL;
3022         goto fail_util_RXDebugPeersNext;
3023     }
3024
3025     if (supportedValues == NULL) {
3026         tst = ADMRXDEBUGHANDLENULL;
3027         goto fail_util_RXDebugPeersNext;
3028     }
3029
3030     rc = IteratorNext(iter, (void *)&item, &tst);
3031     if (!rc) {
3032         goto fail_util_RXDebugPeersNext;
3033     }
3034
3035     *peer = item.peer;
3036     *supportedValues = item.supportedValues;
3037
3038   fail_util_RXDebugPeersNext:
3039
3040     if (st != NULL) {
3041         *st = tst;
3042     }
3043     return rc;
3044 }
3045
3046 /*
3047  * util_RXDebugPeersDone - Finish listing rxdebug peer information.
3048  *
3049  * PARAMETERS
3050  *
3051  * IN iterationId - Iteration id created by util_RXDebugPeersBegin.
3052  *
3053  * LOCKS
3054  *
3055  * No locks are obtained or released by this function
3056  *
3057  * RETURN CODES
3058  *
3059  * Returns != 0 upon successful completion.
3060  *
3061  */
3062
3063 int ADMINAPI
3064 util_RXDebugPeersDone(const void *iterationId, afs_status_p st)
3065 {
3066     int rc = 0;
3067     afs_status_t tst = 0;
3068     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3069
3070     /*
3071      * Validate parameters
3072      */
3073
3074     if (iter == NULL) {
3075         tst = ADMITERATORNULL;
3076         goto fail_util_RXDebugPeersDone;
3077     }
3078
3079     rc = IteratorDone(iter, &tst);
3080
3081   fail_util_RXDebugPeersDone:
3082
3083     if (st != NULL) {
3084         *st = tst;
3085     }
3086     return rc;
3087
3088 }