/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* (C) COPYRIGHT International Business Machines Corp. 1996,2019 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ /*===========================================================================*/ /* @(#)44 1.9 src/rsct/pem/emtools/rmapi_samples/rmapi_smpsig.c, emtools, rsct_rady, rady2035a 6/5/98 11:25:45 */ #include #include #include #include #include #include #include #include #include /* * rmapi_smpsig.c * * This program presents an example of using the Resource Monitor Application * Programming Interface (RMAPI). The configuration data for this monitor * is in the file RmapiSample.loadsdr. This monitor is an example of server * monitor (Resource Monitor Managers connect to the monitor) function that could * be incorporated into a daemon or subsystem. This example monitor demonstrates * using SIGIO as the notification protocol and the use of dynamically instantiable * variables. * * Event Management objects defined for this monitor: * * Monitor: * IBM.PSSP.SampleSigMon # server monitor definition * * Class: * IBM.PSSP.SampleSigDynInstClass # class for dynamically instantable vars * IBM.PSSP.SampleSigNonInstClass # class for non-instantable vars * * Variables: * IBM.PSSP.SampleSigMon.DynInstVar.var # valuetype quantity, datatype long * Resource Identifiers: NodeNum # used as locator field of var * InstName # instance name of variable * IBM.PSSP.SampleSigMon.NonInstVars.var1 # valuetype counter, datatype long * Resource Identifiers: NodeNum # used as locator field of var * IBM.PSSP.SampleSigMon.NonInstVars.var2 # valuetype counter, datatype long * Resource Identifiers: NodeNum # used as locator field of var * IBM.PSSP.SampleSigMon.NonInstVars.var3 # valuetype counter, datatype long * Resource Identifiers: NodeNum # used as locator field of var * * What this monitor does: rmapi_smpsig provides an example of a server monitor * which has 1 dynamically instantable variable and 3 non-instantiable variables. * * The monitor will continue to run until it either receives a signal to terminate, or * all clients have closed their connections. * * This program can be compiled with the following command: * * cc -O rmapi_smpsig.c -o rmapi_smpsig -lha_rr */ #ifndef MIN #define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif /* local defines PROGNAME - Name of this program. MAX_INTERVAL - Max number of seconds before ha_rr_send_value or ha_rr_touch must be called. RESOURCE_MONITOR_NAME - Name of this monitor as defined in the config data. MONITOR_CLASS_NAME - Class name as defined in the config data. SOCKET_TABLE_SIZE - HA_RR_MAX_SESSIONS + 1 for the RMAPI server socket. RMAPI_SERVER_INDEX - Index in the socket call table for the RMAPI server socket. STATIC_VAR_NAME_PREFIX - Common portion of the static vars as defined in the config data. INST_VAR_NAME_PREFIX - Common portion of the inst vars as defined in the config data. INST_VAR_RESID_FORMAT - Resource ID format for instantiable vars. INITIAL_VALUE - Variable initial value used on ha_rr_add_var(). MAX_VALUE - Maximum variable value. NUM_STATIC_VARS - Number of static variables defined for monitor. NUM_INST_VARS - Number of instantiable variables defined for monitor. */ #define PROGNAME "rmapi_smpsig" #define MAX_INTERVAL 500 #define RESOURCE_MONITOR_NAME "IBM.PSSP.SampleSigMon" #define DYN_INST_CLASS_NAME "IBM.PSSP.SampleSigDynInstClass" #define NON_INST_CLASS_NAME "IBM.PSSP.SampleSigNonInstClass" #define NUM_NONINST_VARS 3 #define SOCKET_TABLE_SIZE (HA_RR_MAX_SESSIONS + 1) #define RMAPI_SERVER_INDEX (HA_RR_MAX_SESSIONS) #define DYN_INST_VAR_NAME "IBM.PSSP.SampleSigMon.DynInstVar.var" #define NON_INST_VAR_NAME_PREFIX "IBM.PSSP.SampleSigMon.NonInstVars.var" #define DYN_INST_VAR_RESID "InstName" #define INITIAL_VALUE 10 #define MAX_VALUE 500 #define NULL_RESID "" /* local structs */ struct sock_table_entry { int socket_fd; /* fd for manager session or RMAPI server socket. */ void (*sock_funcp)(int); /* function to be called for this socket fd. */ }; struct local_vars { char var_name[128]; /* Variable name (as in config data). */ char var_resid[32]; /* Qualified resource ID (for instantiable variables). */ short registered; /* flag set when variable is registered. */ long value; /* variables value. */ void *var_handle; /* place for RMAPI to store the var handle. */ }; /* local functions */ void display_rmapi_err(struct ha_em_err_blk *errblk); void server_socket_handler(int table_index); void session_socket_handler(int table_index); void end_session(int table_index); void register_variables(); void inst_variables(struct ha_rr_ctrl_msg *); void add_variables(int sock_fd, struct ha_rr_ctrl_msg *ctrl_msg); void del_variables(int sock_fd, struct ha_rr_ctrl_msg *ctrl_msg); void send_values(); void control_loop(); void set_signals(); void catch_io_signal(int); void catch_alrm_signal(int); void catch_exit_signal(int); void mon_exit(int); /* globals */ int NumMgrs = 0; /* number of resource managers connected. */ struct ha_rr_variable *Variables = (struct ha_rr_variable *)0; /* RMAPI variable array. */ struct ha_rr_val *Values = (struct ha_rr_val *)0; /* RMAPI val array. */ struct sock_table_entry SocketTable[SOCKET_TABLE_SIZE]; /* RMAPI sever and session sockets. */ struct ha_em_err_blk ErrBlock; /* global error block for RMAPI calls. */ struct local_vars *LocalVars = (struct local_vars *)0; /* array of local variables. */ static sigset_t SignalMask; /* mask for signals. */ timer_t IntervalTimerId; /* ID for var update interval timer. */ int Interval; /* Update interval for this monitor. */ int SampleTime = 0; /* flag set by catching interval SIGALRM. */ int Terminate = 0; /* flag set by catching SIGTERM. */ int SigioCaught = 0; /* flag set by catching SIGIO. */ int SigCaught = 0; /* actual signal caught by term. */ int TimeOut = MAX_INTERVAL; /* time out counter to call ha_rr_touch. */ int NumVariables = 0; /* Number of variables available. */ int RmapiInit = 0; /* flag to indicate RMAPI initialized. */ /******************************************************************************/ /* Main - Main - Main - Main - Main - Main - Main - Main - Main - Main - Main */ /******************************************************************************/ main(int argc, char **argv) { int interval1, interval2; int i, rc; struct itimerstruc_t itimer; fprintf(stdout,"%s: %s resource monitor started.\n",PROGNAME,RESOURCE_MONITOR_NAME); /* * Setup signal handlers. */ set_signals(); /* * Initialize the socket table. Socket file descriptors are set to -1. */ for (i=0;i= 0);i++); if (i < HA_RR_MAX_SESSIONS) { /* * Save the manager socket file descriptor returned by the RMAPI. * The socket function was initialized in main. */ SocketTable[i].socket_fd = mgr_sock; NumMgrs++; fprintf(stdout,"New session accepted to index(%d) socket_fd(%d).\n",i,mgr_sock); } else { /* * Should never get here, RMAPI handles too many sessions. */ rc = ha_rr_end_session(mgr_sock,&ErrBlock); } } /* * Handles a message being received from the manager session * specified by [table_index]. */ void session_socket_handler(int table_index) { int len, session_sock; struct ha_rr_ctrl_msg *ctrl_msg_start, *ctrl_msg; /* * Get the socket file descriptor for this session. */ if ((session_sock = SocketTable[table_index].socket_fd) < 0) { return; } /* * Call ha_rr_get_ctrl_msg() to read the command from the manager. */ fprintf(stdout,"Calling ha_rr_get_ctrlmsg for session(%d) socket_fd(%d).\n", table_index,session_sock); len = ha_rr_get_ctrlmsg(session_sock, &ctrl_msg, &ErrBlock); if (len == 0) { /* * Message was for the RMAPI or was incomplete. */ return; } if (len == HA_RR_FAIL) { display_rmapi_err(&ErrBlock); if (ErrBlock.em_errno == HA_RR_EDISCONNECT) { end_session(table_index); } else if (ErrBlock.em_errno != HA_RR_EAGAIN) { /* * Severe RMAPI error. */ mon_exit(1); } return; } /* * Since SIGIO is the notification protocol there could be * more than 1 message to read. */ ctrl_msg_start = ctrl_msg; while ((char *)ctrl_msg < (((char *)ctrl_msg_start) + len)) { switch (ctrl_msg->rr_ctrl_cmd) { case HA_RR_CMD_ADDALL : case HA_RR_CMD_ADDV : add_variables(table_index,ctrl_msg); break; case HA_RR_CMD_DELALL : case HA_RR_CMD_DELV : del_variables(table_index,ctrl_msg); break; case HA_RR_CMD_INSTV : inst_variables(ctrl_msg); break; default : /* * Unknown or unsupported msg - ignore it. */ fprintf(stderr,"Received an unexpected command(%d) from socket_fd(%d), ignoring...\n", ctrl_msg->rr_ctrl_cmd,session_sock); break; } ctrl_msg = (struct ha_rr_ctrl_msg *)(((char *)ctrl_msg) + ctrl_msg->rr_ctrl_msg_len); } /* * Free the message allocated by the RMAPI. */ free(ctrl_msg_start); } /* * Dynamically instantiates the variables requested in the control message. If the message * does not wildcard the resource ID, this routine creates instances of the requested * variables, otherwise it creates several variables to simulate wildcard matching. */ void inst_variables(struct ha_rr_ctrl_msg *ctrl_msg) { int num_var, num_to_create; struct ha_rr_ctrl_var *vp; char *inst_name; static int inst_num = 10; int i, j; fprintf(stdout,"Processing command HA_RR_CMD_INSTV to create %d variables.\n", ctrl_msg->rr_ctrl_num_vars); for (i=0;i < ctrl_msg->rr_ctrl_num_vars;i++) { num_to_create = 0; /* * Get a pointer to the variable structure in the control message. */ vp = &(ctrl_msg->rr_ctrl_vars[i]); if (strcmp(DYN_INST_VAR_NAME, vp->rr_ctrl_name)) { /* * Variable name didn't match the dynamically instantiable variable name. */ fprintf(stderr,"%s: Invalid variable (%s) name sent in INSTV ctrl msg.\n", PROGNAME,vp->rr_ctrl_name); continue; } if (strcmp(vp->rr_ctrl_rsrc_ID,"") != 0) { /* * A specific instance is requested. Accommodate the request by creating * the instance. If this were a real monitor, it would be created if * the request matched a valid variable. */ if (strncmp(vp->rr_ctrl_rsrc_ID,DYN_INST_VAR_RESID,strlen(DYN_INST_VAR_RESID))) { /* * The resource ID in the control message does not match the resource ID * for the variable. */ fprintf(stderr,"%s: Invalid resource ID (%s) sent in INSTV ctrl msg.\n", PROGNAME,vp->rr_ctrl_rsrc_ID); continue; } /* * Get a pointer passed the resource ID name - should be pointing to an '=' now. * The format of the resource ID is: ResourceID_Element_Name=Value */ inst_name = vp->rr_ctrl_rsrc_ID + strlen(DYN_INST_VAR_RESID); if (*inst_name != '=' || *(inst_name + 1) == '\0') { /* * '=' not found or value missing in the ctrl message. */ fprintf(stderr,"%s: Invalid resource ID (%s) sent in INSTV ctrl msg.\n", PROGNAME,vp->rr_ctrl_rsrc_ID); continue; } /* * Adjust the instance name pointer to the value in the control message. */ inst_name++; num_to_create = 1; } else { /* * Resource ID in the message was NULL which means wildcard the value. * Since this is just a sample monitor, we'll make up some variable names * to simulate the wildcard match. The contrived instances will have * resource IDs: InstName=Inst where nn is the value of the local static * variable inst_num. */ num_to_create = 5; } fprintf(stdout,"Instantiating %d new variables.\n",num_to_create); /* * realloc() the local and RMAPI variable arrays to accommodate the new instances. */ num_var = NumVariables + num_to_create; LocalVars = (struct local_vars *)realloc(LocalVars, sizeof(struct local_vars) * num_var); Variables = (struct ha_rr_variable *)realloc(Variables, sizeof(struct ha_rr_variable) * num_var); Values = (struct ha_rr_val *)realloc(Values, sizeof(struct ha_rr_val) * num_var); /* * Initialize the new local variables. */ memset(LocalVars+NumVariables,0,sizeof(struct local_vars) * num_to_create); for (j=NumVariables;jrr_ctrl_cmd) { case HA_RR_CMD_ADDALL : /* * Add all variables to this manager session. */ fprintf(stdout,"Processing cmd HA_RR_CMD_ADDALL to add all variables to session_fd %d.\n",sock_fd); for (i=0;irr_ctrl_num_vars,sock_fd); for (i=0;i < ctrl_msg->rr_ctrl_num_vars;i++) { /* * The instance id field in the ccontrol message is * the index into the LocalVars array. */ inst_id = ctrl_msg->rr_ctrlv.rr_ctrl_vari[i]; if (inst_id < NumVariables) { /* * Copy the variable to the next RMAPI structure. */ Variables[num_to_add].rr_var_name = LocalVars[inst_id].var_name; Variables[num_to_add].rr_var_rsrc_ID = LocalVars[inst_id].var_resid; Variables[num_to_add].rr_varu.rr_var_hndl = &(LocalVars[inst_id].var_handle); Variables[num_to_add].rr_value = &(LocalVars[inst_id].value); num_to_add++; } } break; default : break; } if (num_to_add) { /* * Add the variables by calling ha_rr_add_var. */ num_added = ha_rr_add_var(sock_fd, Variables, num_to_add, 1, &ErrBlock); if (num_added == HA_RR_FAIL) { display_rmapi_err(&ErrBlock); if (ErrBlock.em_errno == HA_RR_EDISCONNECT) { /* * Session closed by manager. */ end_session(table_index); } else { mon_exit(1); } } else { fprintf(stdout,"ha_rr_add_var() added %d vars to session_fd %d.\n",num_added,sock_fd); if (num_to_add != num_added) { /* * Loop through the variables that were attempted * to be added and report any that had errors. */ for (i=0;irr_ctrl_cmd; } switch (ctrl_cmd) { case HA_RR_CMD_DELALL : fprintf(stdout,"Processing command HA_RR_CMD_DELALL to delete all variables for session_fd %d.\n", sock_fd); /* * Delete all variables from this manager session. */ for (i=0;irr_ctrl_num_vars,sock_fd); /* * Delete a vector of variables from this manager session. */ for (i = 0; i < ctrl_msg->rr_ctrl_num_vars; i++) { inst_id = ctrl_msg->rr_ctrlv.rr_ctrl_vari[i]; if ((inst_id < NumVariables) && (LocalVars[i].var_handle != (void *)0)) { /* * Copy the variable handle to the next RMAPI structure. */ Variables[num_to_del].rr_varu.rr_var_hndl = &(LocalVars[inst_id].var_handle); /* * Increment the count of variables to be deleted. */ num_to_del++; } } break; default : break; } if (num_to_del) { /* * Delete the variables by calling ha_rr_del_var. */ num_deleted = ha_rr_del_var(sock_fd, Variables, num_to_del, &ErrBlock); if (num_deleted == HA_RR_FAIL) { display_rmapi_err(&ErrBlock); if (ErrBlock.em_errno == HA_RR_EDISCONNECT) { /* * Session closed by manager. */ end_session(table_index); } else { mon_exit(1); } } /* * rc>0 from ha_rr_del_var is the number of variables that no longer need * their values updated. The RMAPI will have set their handles to NULL. */ fprintf(stdout,"%d variables no longer need to be updated.\n",num_deleted); } } /* * Ends the manager session indexed by the [table_index] parameter * in the socket table. */ void end_session(int table_index) { int rc; fprintf(stdout,"Ending session index(%d) session_fd(%d).\n", table_index,SocketTable[table_index].socket_fd); /* * Make sure this is a valid session. */ if ((table_index < 0) || (table_index > HA_RR_MAX_SESSIONS) || (SocketTable[table_index].socket_fd < 0)) { return; } /* * Delete all variables for this manager. */ del_variables(table_index, (struct ha_rr_ctrl_msg *)0); /* * Call RMAPI to end the session. */ rc = ha_rr_end_session(SocketTable[table_index].socket_fd, &ErrBlock); if (rc == HA_RR_FAIL) { display_rmapi_err(&ErrBlock); mon_exit(1); } /* * Reset the socket file descriptor in the SocketTable and * decrement the manager count. */ SocketTable[table_index].socket_fd = -1; NumMgrs--; if (NumMgrs <= 0) { /* * This was the last manager to end - exit with a good rc. */ fprintf(stdout,"Last manager session closed, exiting...\n"); mon_exit(0); } } /* * Registers variables with the RMAPI. */ void register_variables() { int i, j, num_var; int num_registered, num_to_reg = 0; for (i=0;i=0) { fprintf(stdout,"Calling socket function for session(%d) socket_fd(%d).\n", i,SocketTable[i].socket_fd); (SocketTable[i].sock_funcp)(i); } } } } } /* * Routine to terminate the monitor. */ void mon_exit(int s) { static int recursively_called = 0; int i, rc; /* * Check for recursive call - some routines mon_exit() * calls can likewise call mon_exit(). */ if (recursively_called) return; recursively_called = 1; if (RmapiInit) { /* * Gracefully close all sessions. */ for (i=0;i= 0) { end_session(i); } } /* * Terminate the RMAPI. */ rc = ha_rr_terminate(&ErrBlock); if (rc) { display_rmapi_err(&ErrBlock); } } fprintf(stdout,"%s: %s resource monitor exiting.\n",PROGNAME,RESOURCE_MONITOR_NAME); exit(s); } /* * Display an RMAPI error. */ void display_rmapi_err(struct ha_em_err_blk *errblk) { fprintf(stderr, "RMAPI Error: File(%s) Version(%s) Line(%d) Errno(%d)\n\t%s", errblk->em_errfile, errblk->em_errlevel, errblk->em_errline, errblk->em_errno, errblk->em_errmsg); }