windows-xstat-20060304
[openafs.git] / src / xstat / xstat_fs.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 /*
11  * Description:
12  *      Implementation of the client side of the AFS File Server extended
13  *      statistics facility.
14  *
15  *------------------------------------------------------------------------*/
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID
21     ("$Header$");
22
23 #include "xstat_fs.h"           /*Interface for this module */
24 #include <lwp.h>                /*Lightweight process package */
25
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #else
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #endif
33
34 #define LWP_STACK_SIZE  (16 * 1024)
35
36 /*
37  * Routines we need that don't have explicit include file definitions.
38  */
39 extern int RXAFSCB_ExecuteRequest();    /*AFS callback dispatcher */
40 extern char *hostutil_GetNameByINet();  /*Host parsing utility */
41
42 /*
43  * Help out the linker by explicitly importing the callback routines
44  * File Servers may be lobbing at us.
45  */
46 extern afs_int32 SRXAFSCB_CallBack();
47 extern afs_int32 SRXAFSCB_InitCallBackState3();
48 extern afs_int32 SRXAFSCB_Probe();
49 extern afs_int32 SRXAFSCB_ProbeUUID();
50 extern afs_int32 SRXAFSCB_GetCE();
51 extern afs_int32 SRXAFSCB_GetLock();
52
53 /*
54  * Exported variables.
55  */
56 int xstat_fs_numServers;        /*Num connected servers */
57 struct xstat_fs_ConnectionInfo
58  *xstat_fs_ConnInfo;            /*Ptr to connection array */
59 int numCollections;             /*Number of data collections */
60 struct xstat_fs_ProbeResults xstat_fs_Results;  /*Latest probe results */
61 char terminationEvent;          /*One-shot termination event */
62
63 afs_int32 xstat_fsData[AFS_MAX_XSTAT_LONGS];    /*Buffer for collected data */
64
65 /*
66  * Private globals.
67  */
68 static int xstat_fs_ProbeFreqInSecs;    /*Probe freq. in seconds */
69 static int xstat_fs_initflag = 0;       /*Was init routine called? */
70 static int xstat_fs_debug = 0;  /*Debugging output enabled? */
71 static int xstat_fs_oneShot = 0;        /*One-shot operation? */
72 static int (*xstat_fs_Handler) ();      /*Probe handler routine */
73 static PROCESS probeLWP_ID;     /*Probe LWP process ID */
74 static int xstat_fs_numCollections;     /*Number of desired collections */
75 static afs_int32 *xstat_fs_collIDP;     /*Ptr to collection IDs desired */
76
77 /*
78  * We have to pass a port to Rx to start up our callback listener
79  * service, but 7001 is already taken up by the Cache Manager.  So,
80  * we make up our own.
81  */
82 #define XSTAT_FS_CBPORT 7101
83
84
85 /*------------------------------------------------------------------------
86  * [private] xstat_fs_CleanupInit
87  *
88  * Description:
89  *      Set up for recovery after an error in initialization (i.e.,
90  *      during a call to xstat_fs_Init.
91  *
92  * Arguments:
93  *      None.
94  *
95  * Returns:
96  *      0 on success,
97  *      Error value otherwise.
98  *
99  * Environment:
100  *      This routine is private to the module.
101  *
102  * Side Effects:
103  *      Zeros out basic data structures.
104  *------------------------------------------------------------------------*/
105
106 static int
107 xstat_fs_CleanupInit()
108 {
109     afs_int32 code;             /*Return code from callback stubs */
110     struct rx_call *rxcall;     /*Bogus param */
111     AFSCBFids *Fids_Array;      /*Bogus param */
112     AFSCBs *CallBack_Array;     /*Bogus param */
113
114     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)0;
115     xstat_fs_Results.probeNum = 0;
116     xstat_fs_Results.probeTime = 0;
117     xstat_fs_Results.connP = (struct xstat_fs_ConnectionInfo *)0;
118     xstat_fs_Results.collectionNumber = 0;
119     xstat_fs_Results.data.AFS_CollData_len = AFS_MAX_XSTAT_LONGS;
120     xstat_fs_Results.data.AFS_CollData_val = (afs_int32 *) xstat_fsData;
121     xstat_fs_Results.probeOK = 0;
122
123     rxcall = (struct rx_call *)0;
124     Fids_Array = (AFSCBFids *) 0;
125     CallBack_Array = (AFSCBs *) 0;
126
127     /*
128      * Call each of the callback routines our module provides (in
129      * xstat_fs_callback.c) to make sure they're all there.
130      */
131     code = SRXAFSCB_CallBack(rxcall, Fids_Array, CallBack_Array);
132     if (code)
133         return (code);
134     code = SRXAFSCB_InitCallBackState3(rxcall, (afsUUID *) 0);
135     if (code)
136         return (code);
137     code = SRXAFSCB_Probe(rxcall);
138     return (code);
139 }
140
141
142 /*------------------------------------------------------------------------
143  * [exported] xstat_fs_Cleanup
144  *
145  * Description:
146  *      Clean up our memory and connection state.
147  *
148  * Arguments:
149  *      int a_releaseMem : Should we free up malloc'ed areas?
150  *
151  * Returns:
152  *      0 on total success,
153  *      -1 if the module was never initialized, or there was a problem
154  *              with the xstat_fs connection array.
155  *
156  * Environment:
157  *      xstat_fs_numServers should be properly set.  We don't do anything
158  *      unless xstat_fs_Init() has already been called.
159  *
160  * Side Effects:
161  *      Shuts down Rx connections gracefully, frees allocated space
162  *      (if so directed).
163  *------------------------------------------------------------------------*/
164
165 int
166 xstat_fs_Cleanup(int a_releaseMem)
167 {
168     static char rn[] = "xstat_fs_Cleanup";      /*Routine name */
169     int code;                   /*Return code */
170     int conn_idx;               /*Current connection index */
171     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to xstat_fs connection */
172
173     /*
174      * Assume the best, but check the worst.
175      */
176     if (!xstat_fs_initflag) {
177         fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
178         return (-1);
179     } else
180         code = 0;
181
182     /*
183      * Take care of all Rx connections first.  Check to see that the
184      * server count is a legal value.
185      */
186     if (xstat_fs_numServers <= 0) {
187         fprintf(stderr,
188                 "[%s] Illegal number of servers (xstat_fs_numServers = %d)\n",
189                 rn, xstat_fs_numServers);
190         code = -1;
191     } else {
192         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0) {
193             /*
194              * The xstat_fs connection structure array exists.  Go through
195              * it and close up any Rx connections it holds.
196              */
197             curr_conn = xstat_fs_ConnInfo;
198             for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
199                 if (curr_conn->rxconn != (struct rx_connection *)0) {
200                     rx_DestroyConnection(curr_conn->rxconn);
201                     curr_conn->rxconn = (struct rx_connection *)0;
202                 }
203                 curr_conn++;
204             }                   /*for each xstat_fs connection */
205         }                       /*xstat_fs connection structure exists */
206     }                           /*Legal number of servers */
207
208     /*
209      * If asked to, release the space we've allocated.
210      */
211     if (a_releaseMem) {
212         if (xstat_fs_ConnInfo != (struct xstat_fs_ConnectionInfo *)0)
213             free(xstat_fs_ConnInfo);
214     }
215
216     /*
217      * Return the news, whatever it is.
218      */
219     return (code);
220 }
221
222
223 /*------------------------------------------------------------------------
224  * [private] xstat_fs_LWP
225  *
226  * Description:
227  *      This LWP iterates over the server connections and gathers up
228  *      the desired statistics from each one on a regular basis.  When
229  *      the sweep is done, the associated handler function is called
230  *      to process the new data.
231  *
232  * Arguments:
233  *      None.
234  *
235  * Returns:
236  *      Nothing.
237  *
238  * Environment:
239  *      Started by xstat_fs_Init(), uses global structures and the
240  *      global private xstat_fs_oneShot variable.
241  *
242  * Side Effects:
243  *      Nothing interesting.
244  *------------------------------------------------------------------------*/
245
246 static void
247 xstat_fs_LWP()
248 {
249     static char rn[] = "xstat_fs_LWP";  /*Routine name */
250     register afs_int32 code;    /*Results of calls */
251     int oneShotCode;            /*Result of one-shot signal */
252     struct timeval tv;          /*Time structure */
253     int conn_idx;               /*Connection index */
254     struct xstat_fs_ConnectionInfo *curr_conn;  /*Current connection */
255     afs_int32 srvVersionNumber; /*Xstat version # */
256     afs_int32 clientVersionNumber;      /*Client xstat version */
257     afs_int32 numColls;         /*Number of collections to get */
258     afs_int32 *currCollIDP;     /*Curr collection ID desired */
259
260     static afs_int32 xstat_VersionNumber;       /*Version # of server */
261
262     /*
263      * Set up some numbers we'll need.
264      */
265     clientVersionNumber = AFS_XSTAT_VERSION;
266
267     while (1) {                 /*Service loop */
268         /*
269          * Iterate through the server connections, gathering data.
270          * Don't forget to bump the probe count and zero the statistics
271          * areas before calling the servers.
272          */
273         if (xstat_fs_debug)
274             printf("[%s] Waking up, getting data from %d server(s)\n", rn,
275                    xstat_fs_numServers);
276         curr_conn = xstat_fs_ConnInfo;
277         xstat_fs_Results.probeNum++;
278
279         for (conn_idx = 0; conn_idx < xstat_fs_numServers; conn_idx++) {
280             /*
281              * Grab the statistics for the current File Server, if the
282              * connection is valid.
283              */
284             if (xstat_fs_debug)
285                 printf("[%s] Getting collections from File Server '%s'\n", rn,
286                        curr_conn->hostName);
287             if (curr_conn->rxconn != (struct rx_connection *)0) {
288                 if (xstat_fs_debug)
289                     printf("[%s] Connection OK, calling RXAFS_GetXStats\n",
290                            rn);
291
292                 currCollIDP = xstat_fs_collIDP;
293                 for (numColls = 0; numColls < xstat_fs_numCollections;
294                      numColls++, currCollIDP++) {
295                     /*
296                      * Initialize the per-probe values.
297                      */
298                     if (xstat_fs_debug)
299                         printf("[%s] Asking for data collection %d\n", rn,
300                                *currCollIDP);
301                     xstat_fs_Results.collectionNumber = *currCollIDP;
302                     xstat_fs_Results.data.AFS_CollData_len =
303                         AFS_MAX_XSTAT_LONGS;
304                     memset(xstat_fs_Results.data.AFS_CollData_val, 0,
305                            AFS_MAX_XSTAT_LONGS * 4);
306
307                     xstat_fs_Results.connP = curr_conn;
308
309                     if (xstat_fs_debug) {
310                         printf
311                             ("%s: Calling RXAFS_GetXStats, conn=0x%x, clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%x, timeP=0x%x, dataP=0x%x\n",
312                              rn, curr_conn->rxconn, clientVersionNumber,
313                              *currCollIDP, &srvVersionNumber,
314                              &(xstat_fs_Results.probeTime),
315                              &(xstat_fs_Results.data));
316                         printf("%s: [bufflen=%d, buffer at 0x%x]\n", rn,
317                                xstat_fs_Results.data.AFS_CollData_len,
318                                xstat_fs_Results.data.AFS_CollData_val);
319                     }
320
321                     xstat_fs_Results.probeOK =
322                         RXAFS_GetXStats(curr_conn->rxconn,
323                                         clientVersionNumber, *currCollIDP,
324                                         &srvVersionNumber,
325                                         &(xstat_fs_Results.probeTime),
326                                         &(xstat_fs_Results.data));
327
328                     /*
329                      * Now that we (may) have the data for this connection,
330                      * call the associated handler function.  The handler does
331                      * not take any explicit parameters, but rather gets to the
332                      * goodies via some of the objects exported by this module.
333                      */
334                     if (xstat_fs_debug)
335                         printf("[%s] Calling handler routine.\n", rn);
336                     code = xstat_fs_Handler();
337                     if (code)
338                         fprintf(stderr,
339                                 "[%s] Handler returned error code %d\n", rn,
340                                 code);
341
342                 }               /*For each collection */
343             }
344
345             /*Valid Rx connection */
346             /*
347              * Advance the xstat_fs connection pointer.
348              */
349             curr_conn++;
350
351         }                       /*For each xstat_fs connection */
352
353         /*
354          * All (valid) connections have been probed.  Fall asleep for the
355          * prescribed number of seconds, unless we're a one-shot.  In
356          * that case, we need to signal our caller that we're done.
357          */
358         if (xstat_fs_debug)
359             printf("[%s] Polling complete for probe round %d.\n", rn,
360                    xstat_fs_Results.probeNum);
361
362         if (xstat_fs_oneShot) {
363             /*
364              * One-shot execution desired.  Signal our main procedure
365              * that we've finished our collection round.
366              */
367             if (xstat_fs_debug)
368                 printf("[%s] Signalling main process at 0x%x\n", rn,
369                        &terminationEvent);
370             oneShotCode = LWP_SignalProcess(&terminationEvent);
371             if (oneShotCode)
372                 fprintf(stderr, "[%s] Error %d from LWP_SignalProcess()", rn,
373                         oneShotCode);
374             break;              /*from the perpetual while loop */
375         } /*One-shot execution */
376         else {
377             /*
378              * Continuous execution desired.  Sleep for the required
379              * number of seconds.
380              */
381             tv.tv_sec = xstat_fs_ProbeFreqInSecs;
382             tv.tv_usec = 0;
383             if (xstat_fs_debug)
384                 printf("[%s] Falling asleep for %d seconds\n", rn,
385                        xstat_fs_ProbeFreqInSecs);
386             code = IOMGR_Select(0,      /*Num fids */
387                                 0,      /*Descs ready for reading */
388                                 0,      /*Descs ready for writing */
389                                 0,      /*Descs w/exceptional conditions */
390                                 &tv);   /*Ptr to timeout structure */
391             if (code)
392                 fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn,
393                         code);
394         }                       /*Continuous execution */
395     }                           /*Service loop */
396 }
397
398 /*------------------------------------------------------------------------
399  * [exported] xstat_fs_Init
400  *
401  * Description:
402  *      Initialize the xstat_fs module: set up Rx connections to the
403  *      given set of File Servers, start up the probe and callback LWPs,
404  *      and associate the routine to be called when a probe completes.
405  *      Also, let it know which collections you're interested in.
406  *
407  * Arguments:
408  *      int a_numServers                  : Num. servers to connect to.
409  *      struct sockaddr_in *a_socketArray : Array of server sockets.
410  *      int a_ProbeFreqInSecs             : Probe frequency in seconds.
411  *      int (*a_ProbeHandler)()           : Ptr to probe handler fcn.
412  *      int a_flags                       : Various flags.
413  *      int a_numCollections              : Number of collections desired.
414  *      afs_int32 *a_collIDP                      : Ptr to collection IDs.
415  *
416  * Returns:
417  *      0 on success,
418  *      -2 for (at least one) connection error,
419  *      LWP process creation code, if it failed,
420  *      -1 for other fatal errors.
421  *
422  * Environment:
423  *      *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
424  *      Also, the server security object CBsecobj MUST be a static,
425  *      since it has to stick around after this routine exits.
426  *
427  * Side Effects:
428  *      Sets up just about everything.
429  *------------------------------------------------------------------------*/
430
431 int
432 xstat_fs_Init(int a_numServers, struct sockaddr_in *a_socketArray,
433               int a_ProbeFreqInSecs, int (*a_ProbeHandler) (), int a_flags,
434               int a_numCollections, afs_int32 * a_collIDP)
435 {
436     static char rn[] = "xstat_fs_Init"; /*Routine name */
437     register afs_int32 code;    /*Return value */
438     static struct rx_securityClass *CBsecobj;   /*Callback security object */
439     struct rx_securityClass *secobj;    /*Client security object */
440     struct rx_service *rxsrv_afsserver; /*Server for AFS */
441     int arg_errfound;           /*Argument error found? */
442     int curr_srv;               /*Current server idx */
443     struct xstat_fs_ConnectionInfo *curr_conn;  /*Ptr to current conn */
444     char *hostNameFound;        /*Ptr to returned host name */
445     int conn_err;               /*Connection error? */
446     int PortToUse;              /*Callback port to use */
447     int collIDBytes;            /*Num bytes in coll ID array */
448     char hoststr[16];
449
450     /*
451      * If we've already been called, snicker at the bozo, gently
452      * remind him of his doubtful heritage, and return success.
453      */
454     if (xstat_fs_initflag) {
455         fprintf(stderr, "[%s] Called multiple times!\n", rn);
456         return (0);
457     } else
458         xstat_fs_initflag = 1;
459
460     /*
461      * Check the parameters for bogosities.
462      */
463     arg_errfound = 0;
464     if (a_numServers <= 0) {
465         fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
466                 a_numServers);
467         arg_errfound = 1;
468     }
469     if (a_socketArray == (struct sockaddr_in *)0) {
470         fprintf(stderr, "[%s] Null server socket array argument\n", rn);
471         arg_errfound = 1;
472     }
473     if (a_ProbeFreqInSecs <= 0) {
474         fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
475                 a_ProbeFreqInSecs);
476         arg_errfound = 1;
477     }
478     if (a_ProbeHandler == (int (*)())0) {
479         fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
480         arg_errfound = 1;
481     }
482     if (a_numCollections <= 0) {
483         fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
484                 a_numServers);
485         arg_errfound = 1;
486     }
487     if (a_collIDP == NULL) {
488         fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
489         arg_errfound = 1;
490     }
491     if (arg_errfound)
492         return (-1);
493
494     /*
495      * Record our passed-in info.
496      */
497     xstat_fs_debug = (a_flags & XSTAT_FS_INITFLAG_DEBUGGING);
498     xstat_fs_oneShot = (a_flags & XSTAT_FS_INITFLAG_ONE_SHOT);
499     xstat_fs_numServers = a_numServers;
500     xstat_fs_Handler = a_ProbeHandler;
501     xstat_fs_ProbeFreqInSecs = a_ProbeFreqInSecs;
502     xstat_fs_numCollections = a_numCollections;
503     collIDBytes = xstat_fs_numCollections * sizeof(afs_int32);
504     xstat_fs_collIDP = (afs_int32 *) (malloc(collIDBytes));
505     memcpy(xstat_fs_collIDP, a_collIDP, collIDBytes);
506     if (xstat_fs_debug) {
507         printf("[%s] Asking for %d collection(s): ", rn,
508                xstat_fs_numCollections);
509         for (curr_srv = 0; curr_srv < xstat_fs_numCollections; curr_srv++)
510             printf("%d ", *(xstat_fs_collIDP + curr_srv));
511         printf("\n");
512     }
513
514     /*
515      * Get ready in case we have to do a cleanup - basically, zero
516      * everything out.
517      */
518     code = xstat_fs_CleanupInit();
519     if (code)
520         return (code);
521
522     /*
523      * Allocate the necessary data structures and initialize everything
524      * else.
525      */
526     xstat_fs_ConnInfo = (struct xstat_fs_ConnectionInfo *)
527         malloc(a_numServers * sizeof(struct xstat_fs_ConnectionInfo));
528     if (xstat_fs_ConnInfo == (struct xstat_fs_ConnectionInfo *)0) {
529         fprintf(stderr,
530                 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
531                 rn, a_numServers,
532                 (a_numServers * sizeof(struct xstat_fs_ConnectionInfo)));
533         return (-1);            /*No cleanup needs to be done yet */
534     }
535
536     /*
537      * Initialize the Rx subsystem, just in case nobody's done it.
538      */
539     if (xstat_fs_debug)
540         printf("[%s] Initializing Rx\n", rn);
541     PortToUse = XSTAT_FS_CBPORT;
542
543     do {
544         code = rx_Init(htons(PortToUse));
545         if (code) {
546             if (code == RX_ADDRINUSE) {
547                 if (xstat_fs_debug)
548                     fprintf(stderr,
549                             "[%s] Callback port %d in use, advancing\n", rn,
550                             PortToUse);
551                 PortToUse++;
552             } else {
553                 fprintf(stderr, "[%s] Fatal error in rx_Init()\n", rn);
554                 return (-1);
555             }
556         }
557     } while (code);
558     if (xstat_fs_debug)
559         printf("[%s] Rx initialized on port %d\n", rn, PortToUse);
560
561     /*
562      * Create a null Rx server security object, to be used by the
563      * Callback listener.
564      */
565     CBsecobj = (struct rx_securityClass *)
566         rxnull_NewServerSecurityObject();
567     if (CBsecobj == (struct rx_securityClass *)0) {
568         fprintf(stderr,
569                 "[%s] Can't create callback listener's security object.\n",
570                 rn);
571         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
572         return (-1);
573     }
574     if (xstat_fs_debug)
575         printf("[%s] Callback server security object created\n", rn);
576
577     /*
578      * Create a null Rx client security object, to be used by the
579      * probe LWP.
580      */
581     secobj = rxnull_NewClientSecurityObject();
582     if (secobj == (struct rx_securityClass *)0) {
583         fprintf(stderr,
584                 "[%s] Can't create probe LWP client security object.\n", rn);
585         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
586         return (-1);
587     }
588     if (xstat_fs_debug)
589         printf("[%s] Probe LWP client security object created\n", rn);
590
591     curr_conn = xstat_fs_ConnInfo;
592     conn_err = 0;
593     for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
594         /*
595          * Copy in the socket info for the current server, resolve its
596          * printable name if possible.
597          */
598         if (xstat_fs_debug) {
599             char hoststr[16];
600             printf("[%s] Copying in the following socket info:\n", rn);
601             printf("[%s] IP addr %s, port %d\n", rn,
602                    afs_inet_ntoa_r((a_socketArray + curr_srv)->sin_addr.s_addr,hoststr),
603                    ntohs((a_socketArray + curr_srv)->sin_port));
604         }
605         memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
606                sizeof(struct sockaddr_in));
607
608         hostNameFound =
609             hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
610         if (hostNameFound == NULL) {
611             fprintf(stderr,
612                     "[%s] Can't map Internet address %s to a string name\n",
613                     rn, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
614             curr_conn->hostName[0] = '\0';
615         } else {
616             strcpy(curr_conn->hostName, hostNameFound);
617             if (xstat_fs_debug)
618                 printf("[%s] Host name for server index %d is %s\n", rn,
619                        curr_srv, curr_conn->hostName);
620         }
621
622         /*
623          * Make an Rx connection to the current server.
624          */
625         if (xstat_fs_debug)
626             printf
627                 ("[%s] Connecting to srv idx %d, IP addr %s, port %d, service 1\n",
628                  rn, curr_srv, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr),
629                  ntohs(curr_conn->skt.sin_port));
630
631         curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr,    /*Server addr */
632                                              curr_conn->skt.sin_port,   /*Server port */
633                                              1, /*AFS service # */
634                                              secobj,    /*Security obj */
635                                              0);        /*# of above */
636         if (curr_conn->rxconn == (struct rx_connection *)0) {
637             fprintf(stderr,
638                     "[%s] Can't create Rx connection to server '%s' (%s)\n",
639                     rn, curr_conn->hostName, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
640             conn_err = 1;
641         }
642         if (xstat_fs_debug)
643             printf("[%s] New connection at 0x%lx\n", rn, curr_conn->rxconn);
644
645         /*
646          * Bump the current xstat_fs connection to set up.
647          */
648         curr_conn++;
649
650     }                           /*for curr_srv */
651
652     /*
653      * Create the AFS callback service (listener).
654      */
655     if (xstat_fs_debug)
656         printf("[%s] Creating AFS callback listener\n", rn);
657     rxsrv_afsserver = rx_NewService(0,  /*Use default port */
658                                     1,  /*Service ID */
659                                     "afs",      /*Service name */
660                                     &CBsecobj,  /*Ptr to security object(s) */
661                                     1,  /*# of security objects */
662                                     RXAFSCB_ExecuteRequest);    /*Dispatcher */
663     if (rxsrv_afsserver == (struct rx_service *)0) {
664         fprintf(stderr, "[%s] Can't create callback Rx service/listener\n",
665                 rn);
666         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
667         return (-1);
668     }
669     if (xstat_fs_debug)
670         printf("[%s] Callback listener created\n", rn);
671
672     /*
673      * Start up the AFS callback service.
674      */
675     if (xstat_fs_debug)
676         printf("[%s] Starting up callback listener.\n", rn);
677     rx_StartServer(0);          /*Don't donate yourself to LWP pool */
678
679     /*
680      * Start up the probe LWP.
681      */
682     if (xstat_fs_debug)
683         printf("[%s] Creating the probe LWP\n", rn);
684     code = LWP_CreateProcess(xstat_fs_LWP,      /*Function to start up */
685                              LWP_STACK_SIZE,    /*Stack size in bytes */
686                              1, /*Priority */
687                              (void *)0, /*Parameters */
688                              "xstat_fs Worker", /*Name to use */
689                              &probeLWP_ID);     /*Returned LWP process ID */
690     if (code) {
691         fprintf(stderr, "[%s] Can't create xstat_fs LWP!  Error is %d\n", rn,
692                 code);
693         xstat_fs_Cleanup(1);    /*Delete already-malloc'ed areas */
694         return (code);
695     }
696     if (xstat_fs_debug)
697         printf("[%s] Probe LWP process structure located at 0x%x\n", rn,
698                probeLWP_ID);
699
700     /*
701      * Return the final results.
702      */
703     if (conn_err)
704         return (-2);
705     else
706         return (0);
707 }
708
709
710 /*------------------------------------------------------------------------
711  * [exported] xstat_fs_ForceProbeNow
712  *
713  * Description:
714  *      Wake up the probe LWP, forcing it to execute a probe immediately.
715  *
716  * Arguments:
717  *      None.
718  *
719  * Returns:
720  *      0 on success,
721  *      Error value otherwise.
722  *
723  * Environment:
724  *      The module must have been initialized.
725  *
726  * Side Effects:
727  *      As advertised.
728  *------------------------------------------------------------------------*/
729
730 int
731 xstat_fs_ForceProbeNow()
732 {
733     static char rn[] = "xstat_fs_ForceProbeNow";        /*Routine name */
734
735     /*
736      * There isn't a prayer unless we've been initialized.
737      */
738     if (!xstat_fs_initflag) {
739         fprintf(stderr, "[%s] Must call xstat_fs_Init first!\n", rn);
740         return (-1);
741     }
742
743     /*
744      * Kick the sucker in the side.
745      */
746     IOMGR_Cancel(probeLWP_ID);
747
748     /*
749      * We did it, so report the happy news.
750      */
751     return (0);
752 }