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