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