[TCP/IP] Example of a Remote Procedure Call (RPC) Client/Server
PRODUCT: HP TCP/IP Services Version V5.6 - ECO 4 HP C Version 7.2-022 HP C++ Version 7.3-032 SWS Java Version 1.6
OP/SYS: OpenVMS IA64 Version 8.3-1H1
COMPONENT: Remote Procedure Call (RPC)
SOURCE: Philippe Vouters Fontainebleau/France
LOW-COST HIGH-TECH: http://techno-star.fr
OVERVIEW: This article contains an RPC client/server example where the client activates a routine in the server, and returns the hashed password to the client. A structure is passed to the server and returns a hexadecimal coded string representing the encrypted password. With a second client, it gets the list of processes which start with the letter T on the local computer. The list is obtained twice, the first time using getjpiw (sequential behavior), the second time using getjpi (using an AST). This study stems from a customer's contact first approach using Java/RMI which proved to be very subject to side effects. Mixing the pthread technology, which is implied by the Java runtime, with AST based code such as implied by the use of an Oracle RDB/VMS database runtime proves often difficult and extremely delicate to combine. This software combination was the case for this customer. For the reader, ASTs are very specific to the VMS world. As the Java/RMI approach owns Remote Procedure Call (RPC) notions, this choice proposed here is to replace the first approach with a pure ONC RPC approach, separating the Java code in the client part from the RPC code in the server. Hence this paper happily demonstrating a mixture of TCP/IP ONC RPC, AST and Java based codes. With the new possibility of integrating binary routines directly called by Java using a Java Native Access (JNA) method, the use of a C/C++ Java Native Interface as coded below is no longer a necessity. The JNI code below used here to interface with the ONC RPC client side runtime can be likely happily replaced by direct Java calls to the ONC RPC client side runtime library.
*** CAUTION *** This sample procedure has been tested using TCPIP, V5.6 ECO 4 and HP C V7.2-022, HP C++ V7.3-032, SWS Java V6.0 on OpenVMS IA64 V8.3-1H1. However, we cannot guarantee its effectiveness because of the possibility of error in transmitting or implementing it. It is meant to be used as a template for writing your own procedure, and may require modification for use on your system.
ALTERNATIVE TO JNI ONC RPC CODING: An alternative to a Java Native Interface (JNI) ONC RPC coding in C/C++ would be to use the Java ONC RPC (JRPC) product from Netbula LLC. For more information on JRPC, refer to http://netbula.com/javarpc/
ONC RPC JNI DEVELOPER NOTES: On OpenVMS, things are slightly more complicated as: 1/ Mixing Java and C++ require /NAME=as_is on the C++ compilation 2/ Java native methods must be short to avoid external names greater than 31 characters (LONGEXTERN). Under SWS Java 1.6 and latest HP C/C++ compilers, this is untrue if the C or C++ code is compiled with /NAME=(as_is,shortened). Refer to http://h18012.www1.hp.com/java/documentation/1.6.0/ivms/docs/user_guide.html#namshortcap for more information about HP OpenVMS JRE name shortening ability. For more information about dlsym name shortening ability, refer to: ../tima/OpenVMS-lib_find_image_symbol-dlopen-dlsym-C-example.html 3/ cxxlink options are special to preserve exported functions casing. 4/ ONC RPC extern symbols in C are all uppercased, causing a mixture of mixedcase and uppercase names. This forces all the #define in the defines.h and in the .CXX source. 5/ C++ requires correct functions prototyping which not the case with rpcgen generated functions. 6/ TCPIP$RPC:*.h have poor functions prototyping and do not pass C++ compilation. I thus had to correct the function prototypings in TCPIP$RPC:CLNT.H to correctly call the clnt_ functions. HP Tru64 INFORMATION: Using FTP, download from the VMS node rpc_crypt.x, RPC.java and JNI_RPC_pscan_wild.cxx. Create the following build_Tru64.sh file: #!/bin/sh # # Script to build the Java/JNI ONC RPC on Tru64 # rpcgen rpc_crypt.x javac RPC.java javah -o java_rpc_client.h RPC cc -c rpc_crypt_xdr.c cc -c rpc_crypt_clnt.c cxx -shared -I/usr/opt/java142/include -I/usr/opt/java142/include/alpha \ -pthread -o libJNI_Java_RPC_interface.so rpc_crypt_clnt.o rpc_crypt_xdr.o \ JNI_RPC_pscan_wild.cxx
HP-UX INFORMATION: Using FTP, download from the VMS node rpc_crypt.x, RPC.java and JNI_RPC_pscan_wild.cxx. Create the following build_HP-UX.sh file: #!/bin/sh # # Script to build the Java/JNI ONC RPC on HP-UX # rpcgen rpc_crypt.x javac RPC.java javah -o java_rpc_client.h RPC cc -c +z rpc_crypt_xdr.c cc -c +z rpc_crypt_clnt.c aCC -b +z -I/opt/java1.5/include -I/opt/java1.5/include/hp-ux \ -mt -o libJNI_Java_RPC_interface.sl -lnsl rpc_crypt_clnt.o rpc_crypt_xdr.o \ JNI_RPC_pscan_wild.cxx
PROCEDURE NOTES: OpenVMS Steps: 1/ define Java logicals: @sys$manager:java$xxx_setup.com 2/ If not started, start PORTMAPPER TCP/IP Service To debug the code within an ONC RPC server, just compile, link and execute the server within an interactive session. The command procedure below includes a Java-JNI ONC RPC client.
PROCEDURE RESULTS: LUTECE > @rpc.com clnt_call_method $ run rpc_crypt_svc.exe - /detach- /output=rpc_server.log- /error=rpc_server.err- /dump - /uic=[9P2,VOUTERS]- /priority=4- /buffer_limit=20248- /process= "RPC_SRV_VOUTERS" %RUN-S-PROC_ID, identification of created process is 22600C3D $ set noverify $ mcr DISK$USER3:[VOUTERS]rpc_client_crypt 15.129.24.137 VOUTERS hello hello is encrypted to c9ef5979 $ mcr DISK$USER3:[VOUTERS]rpc_pscan_wild 15.129.24.137 LUTECE t* Scanning (NO AST) t* processes on node lutece returns: | 0 | Process : TCPIP$S_BG32280 on LUTECE | 1 | Process : TNT_SERVER on LUTECE | 2 | Process : TCPIP$S_BG32514 on LUTECE | 3 | Process : TNT122600130 on LUTECE | 4 | Process : TCPIP$INETACP on LUTECE | 5 | Process : TCPIP$PORTM_1 on LUTECE | 6 | Process : TCPIP$FTP_1 on LUTECE | 7 | Process : TCPIP$LBROKER_1 on LUTECE | 8 | Process : TCPIP$METRIC_1 on LUTECE | 9 | Process : TCPIP$NFS_1 on LUTECE | 10 | Process : TCPIP$MOUNTD_1 on LUTECE | 11 | Process : TCPIP$PCNFSD_1 on LUTECE | 12 | Process : TCPIP$POP_1 on LUTECE | 13 | Process : TCPIP$PWIP_ACP on LUTECE | 14 | Process : TCPIP$SNMP_1 on LUTECE | 15 | Process : TCPIP$HR_MIB on LUTECE | 16 | Process : TCPIP$OS_MIBS on LUTECE | 17 | Process : TCPIP$XDM_1 on LUTECE Scanning (WITH AST) t* processes on node lutece returns: | 0 | Process : TCPIP$S_BG32280 on LUTECE | 1 | Process : TNT_SERVER on LUTECE | 2 | Process : TCPIP$S_BG32514 on LUTECE | 3 | Process : TNT122600130 on LUTECE | 4 | Process : TCPIP$INETACP on LUTECE | 5 | Process : TCPIP$PORTM_1 on LUTECE | 6 | Process : TCPIP$FTP_1 on LUTECE | 7 | Process : TCPIP$LBROKER_1 on LUTECE | 8 | Process : TCPIP$METRIC_1 on LUTECE | 9 | Process : TCPIP$NFS_1 on LUTECE | 10 | Process : TCPIP$MOUNTD_1 on LUTECE | 11 | Process : TCPIP$PCNFSD_1 on LUTECE | 12 | Process : TCPIP$POP_1 on LUTECE | 13 | Process : TCPIP$PWIP_ACP on LUTECE | 14 | Process : TCPIP$SNMP_1 on LUTECE | 15 | Process : TCPIP$HR_MIB on LUTECE | 16 | Process : TCPIP$OS_MIBS on LUTECE | 17 | Process : TCPIP$XDM_1 on LUTECE $ set noverify $ java "RPC" 15.129.24.137 LUTECE t* Scanning (NO AST) t* processes on node lutece returns: | 0 | Process : TCPIP$S_BG32280 on LUTECE | 1 | Process : TNT_SERVER on LUTECE | 2 | Process : TCPIP$S_BG32514 on LUTECE | 3 | Process : TNT122600130 on LUTECE | 4 | Process : TCPIP$INETACP on LUTECE | 5 | Process : TCPIP$PORTM_1 on LUTECE | 6 | Process : TCPIP$FTP_1 on LUTECE | 7 | Process : TCPIP$LBROKER_1 on LUTECE | 8 | Process : TCPIP$METRIC_1 on LUTECE | 9 | Process : TCPIP$NFS_1 on LUTECE | 10 | Process : TCPIP$MOUNTD_1 on LUTECE | 11 | Process : TCPIP$PCNFSD_1 on LUTECE | 12 | Process : TCPIP$POP_1 on LUTECE | 13 | Process : TCPIP$PWIP_ACP on LUTECE | 14 | Process : TCPIP$SNMP_1 on LUTECE | 15 | Process : TCPIP$HR_MIB on LUTECE | 16 | Process : TCPIP$OS_MIBS on LUTECE | 17 | Process : TCPIP$XDM_1 on LUTECE Scanning (WITH AST) t* processes on node lutece returns: | 0 | Process : TCPIP$S_BG32280 on LUTECE | 1 | Process : TNT_SERVER on LUTECE | 2 | Process : TCPIP$S_BG32514 on LUTECE | 3 | Process : TNT122600130 on LUTECE | 4 | Process : TCPIP$INETACP on LUTECE | 5 | Process : TCPIP$PORTM_1 on LUTECE | 6 | Process : TCPIP$FTP_1 on LUTECE | 7 | Process : TCPIP$LBROKER_1 on LUTECE | 8 | Process : TCPIP$METRIC_1 on LUTECE | 9 | Process : TCPIP$NFS_1 on LUTECE | 10 | Process : TCPIP$MOUNTD_1 on LUTECE | 11 | Process : TCPIP$PCNFSD_1 on LUTECE | 12 | Process : TCPIP$POP_1 on LUTECE | 13 | Process : TCPIP$PWIP_ACP on LUTECE | 14 | Process : TCPIP$SNMP_1 on LUTECE | 15 | Process : TCPIP$HR_MIB on LUTECE | 16 | Process : TCPIP$OS_MIBS on LUTECE | 17 | Process : TCPIP$XDM_1 on LUTECE $ set noverify
PROCEDURE: $ set noverify $! $! Copyright (C) 2010 by Philippe.Vouters@laposte.net $! $! This program is free software: you can redistribute it and/or modify $! it under the terms of the GNU General Public License as published by the $! Free Software Foundation, either version 3 of the License, or $! any later version. $! $! This program is distributed in the hope that it will be useful, $! but WITHOUT ANY WARRANTY; without even the implied warranty of $! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the $! GNU General Public License for more details. $! $! You should have received a copy of the GNU General Public License $! along with this program. If not, see <http://www.gnu.org/licenses/>. $! $ define/nolog rpc tcpip$rpc $ create rpc_crypt.x struct parameters_to_crypt { opaque password[33]; opaque usrnam[50]; }; struct parameters_to_pscan_wild { opaque nodename[64]; opaque process_name[64]; }; typedef struct parameters_to_crypt *crypt_parameters; typedef struct parameters_to_pscan_wild *pscan_wild_parameters; program MY_CRYPT { version MY_CRYPT_VERS { string CRYPT(crypt_parameters) = 1; string PSCAN_WILD(pscan_wild_parameters) = 2; string PSCAN_WILD_AST(pscan_wild_parameters) = 3; } = 1; } = 0x20000099; $! compile our protocol specification file $ rpcgen rpc_crypt $! compile the two generated files which are needed for $! linking the RPC server crypt service. $ cc rpc_crypt_svc $ cc rpc_crypt_xdr $ create rpc_server_crypt.c #include <stdio.h> #include <ctype.h> #include <string.h> #include <descrip.h> #include <lib$routines.h> #include <jpidef.h> #include <pscandef.h> #include <starlet.h> #include <uaidef.h> #include <ssdef.h> #include <rpc/rpc.h> #include "rpc_crypt.h" struct pscan_item_list_type { short buffer_length; short item_code; union { int item_value; int buffer_address; } value_address; int item_specific_flags; }; struct getjpi_item_list_type { short buffer_length; short item_code; int buffer_address; int return_length_address; }; struct iosb_type { union{ short status,count; int condition; } cond_status; int dev; }; char *nosuchproc = "No such process"; /* uppercase() -- formats string in UPPERCASE letters */ void uppercase (char *text) { int i; for (i=0; i < strlen (text); i++) text[i] = toupper (text[i]); } /* * This is the server part of the RPC. For this example it contains * only one routine which is crypt, a well U*IX known routine, which * does not exist on OpenVMS. */ /* * With RPC calls one must specify pointers to objects. */ char **crypt_1(ap) char **ap; { crypt_parameters crypt_param = (crypt_parameters)*ap; static char encrypted[9]; static char *cp = encrypted; char **dummy; struct dsc$descriptor_s pwddsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; struct dsc$descriptor_s usrnamdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0}; unsigned long int hash[2]; int status; pwddsc.dsc$w_length = strlen(crypt_param->password); pwddsc.dsc$a_pointer = crypt_param->password; usrnamdsc.dsc$w_length = strlen(crypt_param->usrnam); usrnamdsc.dsc$a_pointer = crypt_param->usrnam; status = sys$hash_password (&pwddsc, /* Descriptor tro password */ UAI$C_AD_II, /* Hashing algorythm */ 0, /* salt */ &usrnamdsc, /* Descriptor to user name */ hash); /* Two longwords array */ /* * If status from system service odd, return the encrypted password * as eight hexadecimal digits. */ if ((status & 1)){ sprintf(encrypted,"%8x%c",hash[0],'\0'); dummy = &cp; return(dummy); } return(NULL); } char **pscan_wild_1(ap) char **ap; { pscan_wild_parameters pscan_wild_param = (pscan_wild_parameters)*ap; static char *outbuf=NULL; struct pscan_item_list_type pscan_item_list[3]; struct getjpi_item_list_type getjpi_item_list[3]; struct iosb_type iosb; char nodename[64], name_process[64]; short name_process_length, nodename_length; int status, i; int context = 0; /* 1. Read NODENAME argument and build PSCAN item list element. */ strcpy (nodename, pscan_wild_param->nodename); uppercase (nodename); pscan_item_list[0].buffer_length = strlen (nodename); pscan_item_list[0].item_code = PSCAN$_NODENAME; pscan_item_list[0].value_address.buffer_address = (int)nodename; pscan_item_list[0].item_specific_flags = PSCAN$M_WILDCARD; /* 2. Read NAME_PROCESS argument and build PSCAN item list element. */ strcpy (name_process, pscan_wild_param->process_name); uppercase (name_process); pscan_item_list[1].buffer_length = strlen (name_process); pscan_item_list[1].item_code = PSCAN$_PRCNAM; pscan_item_list[1].value_address.buffer_address = (int)name_process; pscan_item_list[1].item_specific_flags = PSCAN$M_WILDCARD; pscan_item_list[2].buffer_length = 0; pscan_item_list[2].item_code = 0; /* 3. Call $PROCESS_SCAN to establish context for call to $GETJPIW. */ status = sys$process_scan (&context, pscan_item_list); if (! (status&1)) return NULL; getjpi_item_list[0].buffer_length = sizeof (name_process); getjpi_item_list[0].item_code = JPI$_PRCNAM; getjpi_item_list[0].buffer_address = (int)name_process; getjpi_item_list[0].return_length_address = (int) (&name_process_length); getjpi_item_list[1].buffer_length = sizeof (nodename); getjpi_item_list[1].item_code = JPI$_NODENAME; getjpi_item_list[1].buffer_address = (int)nodename; getjpi_item_list[1].return_length_address = (int) (&nodename_length); getjpi_item_list[2].buffer_length = 0; getjpi_item_list[2].item_code = 0; /* 4. For each process that matches the criteria set up by $PROCESS_SCAN, call $GETJPIW to return the process's name and host node. */ if (outbuf) free(outbuf); outbuf=NULL; i = 0; do { char *cp; int len; status = sys$getjpiw (0, &context, 0, getjpi_item_list, &iosb, 0, 0); if (status == SS$_NOMOREPROC) break; if (! (status&1)) return(NULL); if (iosb.cond_status.condition == SS$_NORMAL){ if (!outbuf){ outbuf=calloc(sizeof(char),100); cp = outbuf; sprintf (cp,"| %d\t | Process \t: %.*s on %.*s\n", i++, name_process_length, name_process, nodename_length, nodename); len = strlen(cp); } else{ outbuf=realloc(outbuf,len+100); cp=outbuf+len; sprintf (cp,"| %d\t | Process \t: %.*s on %.*s\n", i++, name_process_length, name_process, nodename_length, nodename); len+=strlen(cp); } } } while (status != SS$_NOMOREPROC); if (!outbuf) return (&nosuchproc); else return(&outbuf); } typedef struct { struct iosb_type *iosb; struct getjpi_item_list_type *getjpi_item_list; int *context; int *i; char *outbuf; int efn; int len; int status; char nodename[64], name_process[64]; short name_process_length, nodename_length; } ast_param_t; void ast(ast_param_t *ast_param){ char *cp; if (ast_param->status == SS$_NOMOREPROC){ sys$setef(ast_param->efn); return; } if (!(ast_param->status &1)){ lib$signal(ast_param->status); } if (ast_param->iosb->cond_status.status == SS$_NOMOREPROC){ sys$setef(ast_param->efn); return; } if (!(ast_param->iosb->cond_status.status &1)){ lib$signal(ast_param->iosb->cond_status.status); } if (ast_param->iosb->cond_status.condition == SS$_NORMAL){ if (!ast_param->outbuf){ ast_param->outbuf=calloc(sizeof(char),100); cp = ast_param->outbuf; sprintf (cp,"| %d\t | Process \t: %.*s on %.*s\n", (*ast_param->i)++, ast_param->name_process_length, ast_param->name_process, ast_param->nodename_length, ast_param->nodename); ast_param->len = strlen(cp); } else{ ast_param->outbuf=realloc(ast_param->outbuf,ast_param->len+100); cp=ast_param->outbuf+ast_param->len; sprintf (cp,"| %d\t | Process \t: %.*s on %.*s\n", (*ast_param->i)++, ast_param->name_process_length, ast_param->name_process, ast_param->nodename_length, ast_param->nodename); ast_param->len+=strlen(cp); } } ast_param->status = sys$getjpi (0, ast_param->context, 0, ast_param->getjpi_item_list, ast_param->iosb, ast,ast_param); } /* * This is the same functiionality as pscan_wild_1 but running with an AST. * This code uses sys$getjpi instead of sys$getjpiw. */ char **pscan_wild_ast_1(ap) char **ap; { pscan_wild_parameters pscan_wild_param = (pscan_wild_parameters)*ap; static char *outbuf; ast_param_t ast_param; struct pscan_item_list_type pscan_item_list[3]; struct getjpi_item_list_type getjpi_item_list[3]; struct iosb_type iosb; int i; int context; #define EFN 10 /* 1. Read NODENAME argument and build PSCAN item list element. */ i = 0; context = 0; memset(&ast_param,0,sizeof(ast_param_t)); strcpy (ast_param.nodename, pscan_wild_param->nodename); uppercase (ast_param.nodename); pscan_item_list[0].buffer_length = strlen (ast_param.nodename); pscan_item_list[0].item_code = PSCAN$_NODENAME; pscan_item_list[0].value_address.buffer_address = (int)ast_param.nodename; pscan_item_list[0].item_specific_flags = PSCAN$M_WILDCARD; /* 2. Read NAME_PROCESS argument and build PSCAN item list element. */ strcpy (ast_param.name_process, pscan_wild_param->process_name); uppercase (ast_param.name_process); pscan_item_list[1].buffer_length = strlen (ast_param.name_process); pscan_item_list[1].item_code = PSCAN$_PRCNAM; pscan_item_list[1].value_address.buffer_address = (int)ast_param.name_process; pscan_item_list[1].item_specific_flags = PSCAN$M_WILDCARD; pscan_item_list[2].buffer_length = 0; pscan_item_list[2].item_code = 0; /* 3. Call $PROCESS_SCAN to establish context for call to $GETJPIW. */ ast_param.status = sys$process_scan (&context, pscan_item_list); if (! (ast_param.status&1)) lib$stop (ast_param.status); getjpi_item_list[0].buffer_length = sizeof (ast_param.name_process); getjpi_item_list[0].item_code = JPI$_PRCNAM; getjpi_item_list[0].buffer_address = (int)ast_param.name_process; getjpi_item_list[0].return_length_address = (int) (&ast_param.name_process_length); getjpi_item_list[1].buffer_length = sizeof (ast_param.nodename); getjpi_item_list[1].item_code = JPI$_NODENAME; getjpi_item_list[1].buffer_address = (int)ast_param.nodename; getjpi_item_list[1].return_length_address = (int) (&ast_param.nodename_length); getjpi_item_list[2].buffer_length = 0; getjpi_item_list[2].item_code = 0; /* 4. Setup AST context */ if (outbuf) free(outbuf); outbuf=NULL; ast_param.iosb = &iosb; ast_param.getjpi_item_list=getjpi_item_list; ast_param.efn=EFN; ast_param.i = &i; ast_param.len=0; ast_param.context=&context; ast_param.outbuf=NULL; sys$clref(ast_param.efn); /* 5. For each process that matches the criteria set up by $PROCESS_SCAN, call $GETJPIW to return the process's name and host node. */ ast_param.status = sys$getjpi (0, &context, 0, getjpi_item_list, &iosb, ast, &ast_param); sys$waitfr(ast_param.efn); outbuf = ast_param.outbuf; if (!outbuf) return(&nosuchproc); else return(&outbuf); } $ cc rpc_server_crypt $ link rpc_crypt_svc,rpc_crypt_xdr,rpc_server_crypt,sys$input:/option sys$share:tcpip$rpcxdr_shr/share $ this_proc = f$env("procedure") $ this_dev=f$parse(this_proc,,,"DEVICE") $ this_dir=f$parse(this_proc,,,"DIRECTORY") $ uic = f$getjpi("","UIC") $ pos_comma = f$locate (",",uic) $ fpos_close_square = f$locate ("]",uic) $ if pos_comma .eq. f$length(uic) $ then $ username = f$extract (1,fpos_close_square-1,uic) $ else $ username = f$extract (pos_comma+1,pos_close_square-pos_comma-1,uic) $ endif $ set verify $ run rpc_crypt_svc.exe - /detach- /output=rpc_server.log- /error=rpc_server.err- /dump - /uic='uic'- /priority=4- /buffer_limit=20248- /process= "RPC_SRV_''username'" $ set noverify $ create rpc_client_crypt.c #include <stdlib.h> #include <stdio.h> #include <rpc/rpc.h> #include "rpc_crypt.h" main(int argc, char **argv){ CLIENT *cl; crypt_parameters param; char **encrypted; if (argc != 4){ printf ("usage: client_crypt <host> <username> <password>\n"); exit(0); } if (strlen(argv[3]) >= 32){ printf ("password %s too long. Specify at most 32 characters\n",argv[3]); exit(0); } param = malloc(sizeof(struct parameters_to_crypt)); strcpy(param->password,argv[3]); strcpy(param->usrnam,argv[2]); /* * Create the client handle used for calling CRYPT on the server * specified on the command line. */ if((cl=clnt_create(argv[1],MY_CRYPT,MY_CRYPT_VERS,"tcp")) == NULL){ /* * Could not etasblish connection with server. */ clnt_pcreateerror(argv[1]); exit(0); } encrypted = crypt_1(¶m,cl); if (encrypted == NULL) { /* * An error occured while calling the server or there is a bug * in sys$hash_password parameters. */ clnt_perror(cl,argv[1]); exit(0); } printf ("%s is encrypted to %s\n",param->password,*encrypted); if (!clnt_freeres(cl,xdr_wrapstring,(char *)encrypted)){ printf("Error freeing RPC/XDR resources\n"); exit(0); } exit(1); } $ cc rpc_client_crypt $ cc rpc_crypt_clnt $ link rpc_client_crypt,rpc_crypt_clnt,rpc_crypt_xdr,sys$input:/options sys$share:tcpip$rpcxdr_shr/share $ create rpc_pscan_wild.c #include <stdlib.h> #include <stdio.h> #include <rpc/rpc.h> #include "rpc_crypt.h" main(int argc, char **argv){ CLIENT *cl; pscan_wild_parameters param; char **outbuf; if (argc != 4){ printf ("usage: %s <host> <node> <process>\n",argv[0]); exit(0); } if (strlen(argv[2]) >= 64){ printf ("nodename %s too long. Specify at most 64 characters\n",argv[3]); exit(0); } if (strlen(argv[3]) >= 64){ printf ("process_name %s too long. Specify at most 64 characters\n",argv[3]); exit(0); } /* * Create the client handle used for calling CRYPT on the server * specified on the command line. */ if((cl=clnt_create(argv[1],MY_CRYPT,MY_CRYPT_VERS,"tcp")) == NULL){ /* * Could not etasblish connection with server. */ clnt_pcreateerror(argv[1]); exit(0); } param = malloc(sizeof(struct parameters_to_pscan_wild)); strcpy(param->process_name,argv[3]); strcpy(param->nodename,argv[2]); outbuf = pscan_wild_1(¶m,cl); if (outbuf == NULL) { /* * An error occured while calling the server or there is a bug * in sys$getjpiw parameters. */ clnt_perror(cl,argv[1]); exit(0); } printf ("Scanning (NO AST) %s processes on node %s returns:\n%s\n", param->process_name,param->nodename,*outbuf); if (!clnt_freeres(cl,xdr_wrapstring,(char *)outbuf)){ printf("Error freeing RPC/XDR resources\n"); clnt_perror(cl,argv[1]); exit(0); } /* * Get the same results but with an AST based method. */ outbuf = pscan_wild_1(¶m,cl); if (outbuf == NULL) { /* * An error occured while calling the server or there is a bug * in sys$getjpiw parameters. */ clnt_perror(cl,argv[1]); exit(0); } printf ("Scanning (WITH AST) %s processes on node %s returns:\n%s\n", param->process_name,param->nodename,*outbuf); if (!clnt_freeres(cl,xdr_wrapstring,(char *)outbuf)){ printf("Error freeing RPC/XDR resources\n"); clnt_perror(cl,argv[1]); exit(0); } free(param); exit(1); } $ cc rpc_pscan_wild $ link rpc_pscan_wild,rpc_crypt_clnt,rpc_crypt_xdr,sys$input:/options sys$share:tcpip$rpcxdr_shr/share $ nodename = f$getsyi ("NODENAME") $ ucx show host 'nodename'/output=t.tmp $ open/read fred t.tmp $loop: $ read/end=eof fred line $ goto loop $eof: $ close fred $ ucx_host_address = f$extract (0, f$locate (" ",line),line) $ if f$search ("t.tmp") .nes. "" then delete/nolog/noconfirm t.tmp; $ set verify $ mcr 'this_dev''this_dir'rpc_client_crypt 'ucx_host_address' 'username' hello $ mcr 'this_dev''this_dir'rpc_pscan_wild 'ucx_host_address' 'nodename' t* $ set noverify $ if f$trnlnm("JAVA$CANCEL_CURRENT") .eqs "" then exit $ dev=f$parse(f$trnlnm("JAVA$CANCEL_CURRENT"),,,"DEVICE","NO_CONCEAL") $ dir=f$parse(f$trnlnm("JAVA$CANCEL_CURRENT"),,,"DIRECTORY","NO_CONCEAL") $ home = dev+f$extract(0,f$locate(".COM]",dir),dir) $ if f$locate("][",dir) .ne. f$length(dir) then - home=dev + f$extract(0,f$locate("][",dir),dir) +- f$extract(f$locate("][",dir)+2,f$locate(".COM]",dir)-f$locate("][",dir)-2,dir) $ define/nolog java$home "''home'.]" $ create RPC.java public class RPC { static { System.loadLibrary("JNI_Java_RPC_interface"); } public static native long Connect_server(String Host); public static native String pscan_wild(long Cl,String Host, String NodeName, String Process_name); public static native String pscan_AST( long Cl, String Host, String NodeName, String ProcessName); public static void main(String args[]) { String Host=args[0]; String NodeName=args[1]; String ProcessName=args[2]; long Cl=Connect_server(Host); String msg1 = pscan_wild(Cl,Host,NodeName,ProcessName); System.out.println ("Scanning (NO AST) " + ProcessName + " processes on node " + NodeName + " returns:\n" + msg1); msg1=""; msg1 = pscan_AST(Cl,Host,NodeName,ProcessName); System.out.println ("Scanning (WITH AST) " + ProcessName + " processes on node " + NodeName + " returns:\n" + msg1); } } $ javac RPC.java $ javah -o Java_RPC_Client.h "RPC" $ create defines.h #define clnt_create CLNT_CREATE #define clnt_pcreateerror CLNT_PCREATEERROR #define clnt_perror CLNT_PERROR #define xdr_wrapstring XDR_WRAPSTRING #define xdr_pscan_wild_parameters XDR_PSCAN_WILD_PARAMETERS $ create JNI_RPC_pscan_wild.cxx #ifdef __VMS #include "defines.h" #endif #include <stdlib.h> #include <stdio.h> #include <string.h> #include <rpc/rpc.h> #ifdef DEBUG #include <lib$routines.h> #include <ssdef.h> #endif #include "java_rpc_client.h" #ifdef CLNT_CALL_METHOD extern "C"{ #endif #include "rpc_crypt.h" #ifdef CLNT_CALL_METHOD }; /* Default timeout can be changed using clnt_control() */ static struct timeval TIMEOUT = { 25, 0 }; #else #ifdef __VMS #define crypt_1 CRYPT_1 #define pscan_wild_1 PSCAN_WILD_1 #define pscan_wild_ast_1 PSCAN_WILD_AST_1 #endif extern "C"{ char **crypt_1(crypt_parameters *argp, CLIENT *clnt); char **pscan_wild_1(pscan_wild_parameters *argp, CLIENT *clnt); char **pscan_wild_ast_1(pscan_wild_parameters *argp, CLIENT *clnt); } #endif JNIEXPORT jlong JNICALL Java_RPC_Connect_1server (JNIEnv *env, jclass clazz, jstring str) { CLIENT *cl; char *Host; #ifdef DEBUG lib$signal(SS$_DEBUG); #endif Host=(char *)env->GetStringUTFChars(str,0); /* * Create the client handle used for calling CRYPT on the server * specified on the command line. */ if((cl=clnt_create(Host,MY_CRYPT,MY_CRYPT_VERS,"tcp")) == NULL){ /* * Could not etasblish connection with server. */ clnt_pcreateerror(Host); exit(0); } env->ReleaseStringUTFChars(str,Host); return (jlong)cl; } JNIEXPORT jstring JNICALL Java_RPC_pscan_1wild (JNIEnv *env, jclass clazz, jlong Cl, jstring str0, jstring str1, jstring str2) { pscan_wild_parameters param; #ifdef CLNT_CALL_METHOD static char *outbuf; #else char **outbuf; #endif jstring ReturnedStr; char *NodeName; char *ProcessName; char *Host; CLIENT *cl; #ifdef DEBUG lib$signal(SS$_DEBUG); #endif cl = (CLIENT *)Cl; Host=(char *)env->GetStringUTFChars(str0,0); NodeName=(char *)env->GetStringUTFChars(str1,0); ProcessName=(char *)env->GetStringUTFChars(str2,0); if (strlen(NodeName) >= 64){ printf ("nodename %s too long. Specify at most 64 characters\n",NodeName); exit(0); } if (strlen(ProcessName) >= 64){ printf ("process_name %s too long. Specify at most 64 characters\n", ProcessName); exit(0); } param = (pscan_wild_parameters)malloc(sizeof(struct parameters_to_pscan_wild)); strcpy(param->process_name,ProcessName); strcpy(param->nodename,NodeName); #ifdef CLNT_CALL_METHOD if (clnt_call(cl, PSCAN_WILD, (xdrproc_t)xdr_pscan_wild_parameters, (char *)¶m, (xdrproc_t)xdr_wrapstring, (char *)&outbuf, TIMEOUT) != RPC_SUCCESS) outbuf = NULL; #else outbuf = pscan_wild_1(¶m,cl); #endif if (outbuf == NULL) { /* * An error occured while calling the server or there is a bug * in sys$getjpiw parameters. */ clnt_perror(cl,Host); exit(0); } #ifdef CLNT_CALL_METHOD ReturnedStr=env->NewStringUTF(outbuf); if (!clnt_freeres(cl,(xdrproc_t)xdr_wrapstring,(char *)&outbuf)){ #else ReturnedStr=env->NewStringUTF(*outbuf); if (!clnt_freeres(cl,(xdrproc_t)xdr_wrapstring,(char *)outbuf)){ #endif printf("Error freeing RPC/XDR resources\n"); clnt_perror(cl,Host); exit(0); } env->ReleaseStringUTFChars(str0,Host); env->ReleaseStringUTFChars(str1,NodeName); env->ReleaseStringUTFChars(str2,ProcessName); outbuf=NULL; free(param); return ReturnedStr; } JNIEXPORT jstring JNICALL Java_RPC_pscan_1AST (JNIEnv *env, jclass clazz, jlong Cl, jstring str0, jstring str1, jstring str2) { pscan_wild_parameters param; #ifdef CLNT_CALL_METHOD static char *outbuf; #else char **outbuf; #endif jstring ReturnedStr; char *NodeName; char *ProcessName; char *Host; CLIENT *cl; cl = (CLIENT *)Cl; Host=(char *)env->GetStringUTFChars(str0,0); NodeName=(char *)env->GetStringUTFChars(str1,0); ProcessName=(char *)env->GetStringUTFChars(str2,0); if (strlen(NodeName) >= 64){ printf ("nodename %s too long. Specify at most 64 characters\n",NodeName); exit(0); } if (strlen(ProcessName) >= 64){ printf ("process_name %s too long. Specify at most 64 characters\n", ProcessName); exit(0); } param = (pscan_wild_parameters)malloc(sizeof(struct parameters_to_pscan_wild)); strcpy(param->process_name,ProcessName); strcpy(param->nodename,NodeName); #ifdef CLNT_CALL_METHOD if (clnt_call(cl, PSCAN_WILD_AST, (xdrproc_t)xdr_pscan_wild_parameters, (char *)(¶m), (xdrproc_t)xdr_wrapstring, (char *)&outbuf, TIMEOUT) != RPC_SUCCESS) outbuf = NULL; #else outbuf = pscan_wild_ast_1(¶m,cl); #endif if (outbuf == NULL) { /* * An error occured while calling the server or there is a bug * in sys$getjpiw parameters. */ clnt_perror(cl,Host); exit(0); } #ifdef CLNT_CALL_METHOD ReturnedStr=env->NewStringUTF(outbuf); if (!clnt_freeres(cl,(xdrproc_t)xdr_wrapstring,(char *)&outbuf)){ #else ReturnedStr=env->NewStringUTF(*outbuf); if (!clnt_freeres(cl,(xdrproc_t)xdr_wrapstring,(char *)outbuf)){ #endif printf("Error freeing RPC/XDR resources\n"); clnt_perror((CLIENT *)Cl,Host); exit(0); } env->ReleaseStringUTFChars(str0,Host); env->ReleaseStringUTFChars(str1,NodeName); env->ReleaseStringUTFChars(str2,ProcessName); outbuf=NULL; free(param); return ReturnedStr; } $ add_object = "rpc_crypt_clnt," $ if P1 .eqs. "CLNT_CALL_METHOD" $ then $ add_define="/define=(CLNT_CALL_METHOD)" $ add_object = "" $ endif $ cxx/include=("java$home/include","java$home/include/VMS") - /name=as_is /warning=disable=(CONPTRLOSBIT) 'add_define' - JNI_RPC_pscan_wild $ cc rpc_crypt_clnt $ cc rpc_crypt_xdr $ cxxlink/shareable/exe=JNI_RPC_interface.exe JNI_RPC_pscan_wild,- 'add_object'rpc_crypt_xdr,sys$input:/options sys$share:tcpip$rpcxdr_shr/share CASE_SENSITIVE=YES SYMBOL_VECTOR=(Java_RPC_Connect_1server=PROCEDURE) SYMBOL_VECTOR=(Java_RPC_pscan_1wild=PROCEDURE) SYMBOL_VECTOR=(Java_RPC_pscan_1AST=PROCEDURE) $ define/nolog JNI_Java_RPC_interface 'this_dev''this_dir'JNI_RPC_interface.exe $ set verify $ java "RPC" 'ucx_host_address' 'nodename' t* $ set noverify $ exit
REFERENCE(S): DIGITAL TCP/IP Services for OpenVMS ONC RPC Programming Order Number AA-Q06VE-TE