/* ** File name: SYSINFO.C ** ** Copyright (c) 1991, by ** Process Software Corporation ** Framingham, Massachusetts */ /* ** Include files */ #include #include #include "TCPWARE_INCLUDE:RPC.H" #include "SYSINFO.H" #include "SYSINFO_DEF.H" #include "TCPWARE_INCLUDE:SOCKET.H" #include "TCPWARE_INCLUDE:NETDB.H" /* ** This macro sets the character pointer x to the address of the string ** containing the parameter's argument. The argument may be specified as ** either: -xargument or -x argument. */ #define get_arg_string( x) \ {if( (*argv)[2]) (x) = *argv+2; \ else if( argc > 1) { argc--; (x) = *++argv;}} /* ** Declare Functions */ static longw parse_command_line(); static int each_result(); extern void sys$exit(); /* ** Variables */ static readonly char usage[] = "Command format: sysinfo [-d#] [limit]\n", INV_PARAM[] = "Invalid parameter: %s\n"; /* ** These variable are used to determine how long the client should wait for ** replies. If no_limit is TRUE, the client will always continue to wait and ** eventually timeout. Otherwise, num_replies is the number of replies that ** the client will continue to wait for. This variable is decremented every ** time a reply is received. */ longw num_replies; byte no_limit; /* **************************************** ** ** Main program ** ** Abstract: ** This program demonstrates the use of the clnt_broadcast function. */ main( argc, argv) int argc; char *argv[]; { longw status; /* VMS status code */ enum clnt_stat rpc_status; /* status returned by clnt_broadcast */ system_info results; /* reply received from server */ /* ** Parse the command line that the user entered. */ _error( status = parse_command_line( argc, argv)) { if( status == SS$_BADPARAM) printf( usage); exit( status); } /* ** results must be zeroed so that xdr_getsyi_res will allocate the memory. ** Otherwise, xdr_getsyi_res assumes that results contains the addresses of ** valid buffers. */ bzero( &results, sizeof( results)); /* ** Do the RPC broadcast. clnt_broadcast does not need a host name since the ** request will be broadcast. It does need the usual program, version, and ** procedure numbers. The XDR function for the arguments is xdr_void (so the ** argument pointer will be ignored). The XDR function for the results is ** xdr_system_info. Unlike the clnt_call function, clnt_broadcast requires ** the address of a function to be called every time a reply is received. ** This function will return a 0 if clnt_broadcast should listen for more ** replies, or a non-zero when its done. */ rpc_status = clnt_broadcast( SYSTEM_INFO_PROG, SYSTEM_INFO_VERS_1, SYSTEM_INFO_PROC_1, xdr_void, 0, xdr_system_info, &results, each_result); /* ** The clnt_broadcast call will return when it encounters an error, it times ** out, or the function each_result returns a 1. This program will time out. */ printf( "\nRPC broadcast returned the status:\n"); clnt_perrno( rpc_status); exit( SS$_NORMAL); } /* end the main program */ /* **************************************** ** ** Function: parse_command_line() ** ** Abstract: ** This function parses the command line in the following form: ** ** sysinfo [-d#] [limit] ** -d# is the optional RPC debugging value to use. (hex) ** limit is the optional number of replies to wait for. (decimal) ** ** Return value: ** A VMS status code. If the status code SS$_BADPARAM is returned, the ** main program displays the correct command format. */ static longw parse_command_line( argc, argv) int argc; char *argv[]; { longw debug = 0; char *cp; while( --argc > 0 && **++argv == '-') { switch( (*argv)[1]) { case 'd': /* specifying a debugging value */ case 'D': get_arg_string( cp); if( cp) /* catch the case when -d is entered w/o a # */ sscanf( cp, "%x", &debug); break; default: goto invalid_parameter; } } /* ** The user may specify only 1 parameter, the number of replies to wait for. */ if( argc > 1) { ++argv; goto invalid_parameter; } /* ** Assume that the user will not specify a limit by setting no_limit to TRUE. */ no_limit = TRUE; if( argc != 0) { if( !isdigit( **argv)) /* number must start w/ a digit */ goto invalid_parameter; sscanf( *argv, "%d", &num_replies); if( num_replies != 0) /* a limit of zero is no limit */ no_limit = FALSE; } /* ** If the debugging value is non-zero, set it. */ if( debug) cp = oncrpc_set_char( RPCCHAR__DEBUG, &debug); /* ** The client will use non-privileged ports. */ oncrpc_set_char( RPCCHAR__DEFPORTS, &RPCPORTS__NORMAL); return( SS$_NORMAL); invalid_parameter: printf( INV_PARAM, *argv); return( SS$_BADPARAM); } /* end function parse_command_line() */ /* **************************************** ** ** Function: each_result() ** ** Abstract: ** This function is called everytime clnt_broadcast receives a reply. ** ** For this client, this function consists of cancelling the timer, ** displaying the reply that the server sent, and restarting the timer. ** This function always returns 0 since the timer is used to exit the ** program. In other applications, this function would eventually return ** a 1, indicating that clnt_broadcast should stop waiting for replies ** and return to the main program. ** ** Return value: ** 0 - clnt_broadcast will always wait for more replies */ static int each_result( si, host_addr) system_info *si; struct sockaddr_in *host_addr; { char *sp; struct hostent *host; /* ** Display the host name of the server who sent the reply. If no name is ** available, display the internet address in the form a.b.c.d. */ host = gethostbyaddr( &host_addr->sin_addr.s_addr, 4, AF_INET); if( host) sp = host->h_name; else sp = inet_ntoa( host_addr->sin_addr.s_addr); printf( "\nReceived a reply from %s\n", sp); /* ** Display the reply that was sent. */ printf( "The server sent:\n host: '%s'\n operating system: '%s'\n", si->si_node_name, si->si_op_sys); /* ** Wait for more replies if the user had specified a limit and there more ** replies are expected after this one. */ if( no_limit == TRUE) return( 0); /* wait for more replies */ if( --num_replies == 0) return( 1); /* this was the last reply */ return( 0); } /* end function each_result() */ /* end file SYSINFO.C */