2 * Copyright 2000, International Business Machines Corporation and others.
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
12 * Implementation of the client side of the AFS Cache Manager
13 * extended statistics facility.
15 *------------------------------------------------------------------------*/
17 #include <afsconfig.h>
18 #include <afs/param.h>
21 #include "xstat_cm.h" /*Interface for this module */
22 #include <lwp.h> /*Lightweight process package */
24 #include <afs/afsutil.h>
27 #define LWP_STACK_SIZE (16 * 1024)
30 * Routines we need that don't have explicit include file definitions.
32 extern char *hostutil_GetNameByINet(); /*Host parsing utility */
37 int xstat_cm_numServers; /*Num connected servers */
38 struct xstat_cm_ConnectionInfo
39 *xstat_cm_ConnInfo; /*Ptr to connection array */
40 int numCollections; /*Number of data collections */
41 struct xstat_cm_ProbeResults xstat_cm_Results; /*Latest probe results */
42 char terminationEvent; /*One-shot termination event */
44 afs_int32 xstat_cmData[AFSCB_MAX_XSTAT_LONGS]; /*Buffer for collected data */
49 static int xstat_cm_ProbeFreqInSecs; /*Probe freq. in seconds */
50 static int xstat_cm_initflag = 0; /*Was init routine called? */
51 static int xstat_cm_debug = 0; /*Debugging output enabled? */
52 static int xstat_cm_oneShot = 0; /*One-shot operation? */
53 static int (*xstat_cm_Handler) (); /*Probe handler routine */
54 static PROCESS probeLWP_ID; /*Probe LWP process ID */
55 static int xstat_cm_numCollections; /*Number of desired collections */
56 static afs_int32 *xstat_cm_collIDP; /*Ptr to collection IDs desired */
59 /*------------------------------------------------------------------------
60 * [private] xstat_cm_CleanupInit
63 * Set up for recovery after an error in initialization (i.e.,
64 * during a call to xstat_cm_Init.
71 * Error value otherwise.
74 * This routine is private to the module.
77 * Zeros out basic data structures.
78 *------------------------------------------------------------------------*/
81 xstat_cm_CleanupInit()
83 xstat_cm_ConnInfo = (struct xstat_cm_ConnectionInfo *)0;
84 xstat_cm_Results.probeNum = 0;
85 xstat_cm_Results.probeTime = 0;
86 xstat_cm_Results.connP = (struct xstat_cm_ConnectionInfo *)0;
87 xstat_cm_Results.collectionNumber = 0;
88 xstat_cm_Results.data.AFSCB_CollData_len = AFSCB_MAX_XSTAT_LONGS;
89 xstat_cm_Results.data.AFSCB_CollData_val = (afs_int32 *) xstat_cmData;
90 xstat_cm_Results.probeOK = 0;
96 /*------------------------------------------------------------------------
97 * [exported] xstat_cm_Cleanup
100 * Clean up our memory and connection state.
103 * int a_releaseMem : Should we free up malloc'ed areas?
106 * 0 on total success,
107 * -1 if the module was never initialized, or there was a problem
108 * with the xstat_cm connection array.
111 * xstat_cm_numServers should be properly set. We don't do anything
112 * unless xstat_cm_Init() has already been called.
115 * Shuts down Rx connections gracefully, frees allocated space
117 *------------------------------------------------------------------------*/
120 xstat_cm_Cleanup(int a_releaseMem)
122 static char rn[] = "xstat_cm_Cleanup"; /*Routine name */
123 int code; /*Return code */
124 int conn_idx; /*Current connection index */
125 struct xstat_cm_ConnectionInfo *curr_conn; /*Ptr to xstat_cm connection */
128 * Assume the best, but check the worst.
130 if (!xstat_cm_initflag) {
131 fprintf(stderr, "[%s] Refused; module not initialized\n", rn);
137 * Take care of all Rx connections first. Check to see that the
138 * server count is a legal value.
140 if (xstat_cm_numServers <= 0) {
142 "[%s] Illegal number of servers (xstat_cm_numServers = %d)\n",
143 rn, xstat_cm_numServers);
146 if (xstat_cm_ConnInfo != (struct xstat_cm_ConnectionInfo *)0) {
148 * The xstat_cm connection structure array exists. Go through
149 * it and close up any Rx connections it holds.
151 curr_conn = xstat_cm_ConnInfo;
152 for (conn_idx = 0; conn_idx < xstat_cm_numServers; conn_idx++) {
153 if (curr_conn->rxconn != (struct rx_connection *)0) {
154 rx_DestroyConnection(curr_conn->rxconn);
155 curr_conn->rxconn = (struct rx_connection *)0;
158 } /*for each xstat_cm connection */
159 } /*xstat_cm connection structure exists */
160 } /*Legal number of servers */
163 * If asked to, release the space we've allocated.
166 if (xstat_cm_ConnInfo != (struct xstat_cm_ConnectionInfo *)0)
167 free(xstat_cm_ConnInfo);
171 * Return the news, whatever it is.
177 /*------------------------------------------------------------------------
178 * [private] xstat_cm_LWP
181 * This LWP iterates over the server connections and gathers up
182 * the desired statistics from each one on a regular basis, for
183 * all known data collections. The associated handler function
184 * is called each time a new data collection is received.
193 * Started by xstat_cm_Init(), uses global structures and the
194 * global private xstat_cm_oneShot variable.
198 *------------------------------------------------------------------------*/
200 xstat_cm_LWP(void *unused)
202 static char rn[] = "xstat_cm_LWP"; /*Routine name */
203 register afs_int32 code; /*Results of calls */
204 int oneShotCode; /*Result of one-shot signal */
205 struct timeval tv; /*Time structure */
206 int conn_idx; /*Connection index */
207 struct xstat_cm_ConnectionInfo *curr_conn; /*Current connection */
208 afs_int32 srvVersionNumber; /*Xstat version # */
209 afs_int32 clientVersionNumber; /*Client xstat version */
210 afs_int32 numColls; /*Number of collections to get */
211 afs_int32 *currCollIDP; /*Curr collection ID desired */
214 * Set up some numbers we'll need.
216 clientVersionNumber = AFSCB_XSTAT_VERSION;
218 while (1) { /*Service loop */
220 * Iterate through the server connections, gathering data.
221 * Don't forget to bump the probe count and zero the statistics
222 * areas before calling the servers.
225 printf("[%s] Waking up, getting data from %d server(s)\n", rn,
226 xstat_cm_numServers);
227 curr_conn = xstat_cm_ConnInfo;
228 xstat_cm_Results.probeNum++;
230 for (conn_idx = 0; conn_idx < xstat_cm_numServers; conn_idx++) {
232 * Grab the statistics for the current Cache Manager, if the
233 * connection is valid.
236 printf("[%s] Getting collections from Cache Manager '%s'\n",
237 rn, curr_conn->hostName);
238 if (curr_conn->rxconn != (struct rx_connection *)0) {
240 printf("[%s] Connection OK, calling RXAFSCB_GetXStats\n",
244 * Probe the given CM for each desired collection.
246 currCollIDP = xstat_cm_collIDP;
247 for (numColls = 0; numColls < xstat_cm_numCollections;
248 numColls++, currCollIDP++) {
250 * Initialize the per-probe values.
253 printf("[%s] Asking for data collection %d\n", rn,
255 xstat_cm_Results.collectionNumber = *currCollIDP;
256 xstat_cm_Results.data.AFSCB_CollData_len =
257 AFSCB_MAX_XSTAT_LONGS;
258 memset(xstat_cm_Results.data.AFSCB_CollData_val, 0,
259 AFSCB_MAX_XSTAT_LONGS * 4);
261 xstat_cm_Results.connP = curr_conn;
263 if (xstat_cm_debug) {
265 ("%s: Calling RXAFSCB_GetXStats, conn=0x%" AFS_PTR_FMT ", clientVersionNumber=%d, collectionNumber=%d, srvVersionNumberP=0x%" AFS_PTR_FMT ", timeP=0x%" AFS_PTR_FMT ", dataP=0x%" AFS_PTR_FMT "\n",
266 rn, curr_conn->rxconn, clientVersionNumber,
267 *currCollIDP, &srvVersionNumber,
268 &(xstat_cm_Results.probeTime),
269 &(xstat_cm_Results.data));
270 printf("%s: [bufflen=%d, buffer at 0x%" AFS_PTR_FMT "]\n", rn,
271 xstat_cm_Results.data.AFSCB_CollData_len,
272 xstat_cm_Results.data.AFSCB_CollData_val);
275 xstat_cm_Results.probeOK =
276 RXAFSCB_GetXStats(curr_conn->rxconn,
277 clientVersionNumber, *currCollIDP,
279 &(xstat_cm_Results.probeTime),
280 &(xstat_cm_Results.data));
283 * Now that we (may) have the data for this connection,
284 * call the associated handler function. The handler
285 * does not take any explicit parameters, but rather
286 * gets to the goodies via some of the objects exported
290 printf("[%s] Calling handler routine.\n", rn);
291 code = xstat_cm_Handler();
294 "[%s] Handler routine got error code %d\n",
296 } /*For each collection */
299 /*Valid Rx connection */
301 * Advance the xstat_cm connection pointer.
305 } /*For each xstat_cm connection */
308 * All (valid) connections have been probed. Fall asleep for the
309 * prescribed number of seconds, unless we're a one-shot. In
310 * that case, we need to signal our caller that we're done.
313 printf("[%s] Polling complete for probe round %d.\n", rn,
314 xstat_cm_Results.probeNum);
316 if (xstat_cm_oneShot) {
318 * One-shot execution desired. Signal our main procedure
319 * that we've finished our collection round.
322 printf("[%s] Signalling main process at 0x%" AFS_PTR_FMT "\n", rn,
324 oneShotCode = LWP_SignalProcess(&terminationEvent);
326 fprintf(stderr, "[%s] Error %d from LWP_SignalProcess()", rn,
328 break; /*from the perpetual while loop */
329 } /*One-shot execution */
332 * Continuous execution desired. Sleep for the required
335 tv.tv_sec = xstat_cm_ProbeFreqInSecs;
338 printf("[%s] Falling asleep for %d seconds\n", rn,
339 xstat_cm_ProbeFreqInSecs);
340 code = IOMGR_Select(0, /*Num fids */
341 0, /*Descs ready for reading */
342 0, /*Descs ready for writing */
343 0, /*Descs w/exceptional conditions */
344 &tv); /*Ptr to timeout structure */
346 fprintf(stderr, "[%s] IOMGR_Select returned code %d\n", rn,
348 } /*Continuous execution */
354 /*------------------------------------------------------------------------
355 * [exported] xstat_cm_Init
358 * Initialize the xstat_cm module: set up Rx connections to the
359 * given set of Cache Managers, start up the probe LWP, and
360 * associate the routine to be called when a probe completes.
361 * Also, let it know which collections you're interested in.
364 * int a_numServers : Num. servers to connect to.
365 * struct sockaddr_in *a_socketArray : Array of server sockets.
366 * int a_ProbeFreqInSecs : Probe frequency in seconds.
367 * int (*a_ProbeHandler)() : Ptr to probe handler fcn.
368 * int a_flags; : Various flags.
369 * int a_numCollections : Number of collections desired.
370 * afs_int32 *a_collIDP : Ptr to collection IDs.
374 * -2 for (at least one) connection error,
375 * LWP process creation code, if it failed,
376 * -1 for other fatal errors.
379 * *** MUST BE THE FIRST ROUTINE CALLED FROM THIS PACKAGE ***
382 * Sets up just about everything.
383 *------------------------------------------------------------------------*/
386 xstat_cm_Init(int a_numServers, struct sockaddr_in *a_socketArray,
387 int a_ProbeFreqInSecs, int (*a_ProbeHandler) (), int a_flags,
388 int a_numCollections, afs_int32 * a_collIDP)
391 static char rn[] = "xstat_cm_Init"; /*Routine name */
392 register afs_int32 code; /*Return value */
393 struct rx_securityClass *secobj; /*Client security object */
394 int arg_errfound; /*Argument error found? */
395 int curr_srv; /*Current server idx */
396 struct xstat_cm_ConnectionInfo *curr_conn; /*Ptr to current conn */
397 char *hostNameFound; /*Ptr to returned host name */
398 int conn_err; /*Connection error? */
399 int collIDBytes; /*Num bytes in coll ID array */
403 * If we've already been called, snicker at the bozo, gently
404 * remind him of his doubtful heritage, and return success.
406 if (xstat_cm_initflag) {
407 fprintf(stderr, "[%s] Called multiple times!\n", rn);
410 xstat_cm_initflag = 1;
413 * Check the parameters for bogosities.
416 if (a_numServers <= 0) {
417 fprintf(stderr, "[%s] Illegal number of servers: %d\n", rn,
421 if (a_socketArray == (struct sockaddr_in *)0) {
422 fprintf(stderr, "[%s] Null server socket array argument\n", rn);
425 if (a_ProbeFreqInSecs <= 0) {
426 fprintf(stderr, "[%s] Illegal probe frequency: %d\n", rn,
430 if (a_ProbeHandler == (int (*)())0) {
431 fprintf(stderr, "[%s] Null probe handler function argument\n", rn);
434 if (a_numCollections <= 0) {
435 fprintf(stderr, "[%s] Illegal collection count argument: %d\n", rn,
439 if (a_collIDP == NULL) {
440 fprintf(stderr, "[%s] Null collection ID array argument\n", rn);
447 * Record our passed-in info.
449 xstat_cm_debug = (a_flags & XSTAT_CM_INITFLAG_DEBUGGING);
450 xstat_cm_oneShot = (a_flags & XSTAT_CM_INITFLAG_ONE_SHOT);
451 xstat_cm_numServers = a_numServers;
452 xstat_cm_Handler = a_ProbeHandler;
453 xstat_cm_ProbeFreqInSecs = a_ProbeFreqInSecs;
454 xstat_cm_numCollections = a_numCollections;
455 collIDBytes = xstat_cm_numCollections * sizeof(afs_int32);
456 xstat_cm_collIDP = (afs_int32 *) (malloc(collIDBytes));
457 memcpy(xstat_cm_collIDP, a_collIDP, collIDBytes);
458 if (xstat_cm_debug) {
459 printf("[%s] Asking for %d collection(s): ", rn,
460 xstat_cm_numCollections);
461 for (curr_srv = 0; curr_srv < xstat_cm_numCollections; curr_srv++)
462 printf("%d ", *(xstat_cm_collIDP + curr_srv));
467 * Get ready in case we have to do a cleanup - basically, zero
470 code = xstat_cm_CleanupInit();
475 * Allocate the necessary data structures and initialize everything
478 xstat_cm_ConnInfo = (struct xstat_cm_ConnectionInfo *)
479 malloc(a_numServers * sizeof(struct xstat_cm_ConnectionInfo));
480 if (xstat_cm_ConnInfo == (struct xstat_cm_ConnectionInfo *)0) {
482 "[%s] Can't allocate %d connection info structs (%d bytes)\n",
484 (a_numServers * sizeof(struct xstat_cm_ConnectionInfo)));
485 return (-1); /*No cleanup needs to be done yet */
489 * Initialize the Rx subsystem, just in case nobody's done it.
492 printf("[%s] Initializing Rx on port 0\n", rn);
493 code = rx_Init(htons(0));
495 fprintf(stderr, "[%s] Fatal error in rx_Init(), error=%d\n", rn,
501 printf("[%s] Rx initialized on port 0\n", rn);
504 * Create a null Rx client security object, to be used by the
507 secobj = rxnull_NewClientSecurityObject();
508 if (secobj == (struct rx_securityClass *)0) {
510 "[%s] Can't create probe LWP client security object.\n", rn);
511 xstat_cm_Cleanup(1); /*Delete already-malloc'ed areas */
515 printf("[%s] Probe LWP client security object created\n", rn);
517 curr_conn = xstat_cm_ConnInfo;
519 for (curr_srv = 0; curr_srv < a_numServers; curr_srv++) {
521 * Copy in the socket info for the current server, resolve its
522 * printable name if possible.
524 if (xstat_cm_debug) {
525 printf("[%s] Copying in the following socket info:\n", rn);
526 printf("[%s] IP addr 0s, port %d\n",
527 afs_inet_ntoa_r((a_socketArray + curr_srv)->sin_addr.s_addr,hoststr),
528 ntohs((a_socketArray + curr_srv)->sin_port));
530 memcpy(&(curr_conn->skt), a_socketArray + curr_srv,
531 sizeof(struct sockaddr_in));
534 hostutil_GetNameByINet(curr_conn->skt.sin_addr.s_addr);
535 if (hostNameFound == NULL) {
537 "[%s] Can't map Internet address %s to a string name\n",
538 rn, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
539 curr_conn->hostName[0] = '\0';
541 strcpy(curr_conn->hostName, hostNameFound);
543 printf("[%s] Host name for server index %d is %s\n", rn,
544 curr_srv, curr_conn->hostName);
548 * Make an Rx connection to the current server.
552 ("[%s] Connecting to srv idx %d, IP addr %s, port %d, service 1\n",
553 rn, curr_srv, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr),
554 ntohs(curr_conn->skt.sin_port));
555 curr_conn->rxconn = rx_NewConnection(curr_conn->skt.sin_addr.s_addr, /*Server addr */
556 curr_conn->skt.sin_port, /*Server port */
557 1, /*AFS service # */
558 secobj, /*Security obj */
560 if (curr_conn->rxconn == (struct rx_connection *)0) {
562 "[%s] Can't create Rx connection to server '%s' (%s)\n",
563 rn, curr_conn->hostName, afs_inet_ntoa_r(curr_conn->skt.sin_addr.s_addr,hoststr));
567 printf("[%s] New connection at 0x%" AFS_PTR_FMT "\n", rn, curr_conn->rxconn);
570 * Bump the current xstat_cm connection to set up.
577 * Start up the probe LWP.
580 printf("[%s] Creating the probe LWP\n", rn);
581 code = LWP_CreateProcess(xstat_cm_LWP, /*Function to start up */
582 LWP_STACK_SIZE, /*Stack size in bytes */
584 (void *)0, /*Parameters */
585 "xstat_cm Worker", /*Name to use */
586 &probeLWP_ID); /*Returned LWP process ID */
588 fprintf(stderr, "[%s] Can't create xstat_cm LWP! Error is %d\n", rn,
590 xstat_cm_Cleanup(1); /*Delete already-malloc'ed areas */
594 printf("[%s] Probe LWP process structure located at 0x%" AFS_PTR_FMT "\n", rn,
598 * Return the final results.
607 /*------------------------------------------------------------------------
608 * [exported] xstat_cm_ForceProbeNow
611 * Wake up the probe LWP, forcing it to execute a probe immediately.
618 * Error value otherwise.
621 * The module must have been initialized.
625 *------------------------------------------------------------------------*/
628 xstat_cm_ForceProbeNow()
630 static char rn[] = "xstat_cm_ForceProbeNow"; /*Routine name */
633 * There isn't a prayer unless we've been initialized.
635 if (!xstat_cm_initflag) {
636 fprintf(stderr, "[%s] Must call xstat_cm_Init first!\n", rn);
641 * Kick the sucker in the side.
643 IOMGR_Cancel(probeLWP_ID);
646 * We did it, so report the happy news.