|
Hi Mike, I'm moving this over to RPG400-L since my examples may be bit too RPG-ish for MIDRANGE-L :) [SNIP] > Step 1: > Program 1, System A: > Using the rexec() API, call the Program 2, System B > > Step 2: > Program 2, System B: > Program is called and processes > Write the response to the printer file (O specs) > End the program > > Step 3: > Since there are three "data channels" open, Program 1, System 1, read stdin > Process the response > End the program > > Is this correct? > Do you have any examples of this process? [SNIP] Yes, I do have an example. I've adjusted it a bit from my production code, I've brought the prototypes into the main source member, and I've adjusted it to be more of what you're doing. (I normally use rexec() to talk to a FreeBSD server, not another iSeries) But, I tested it quick, and it looks like it works. Here's the code for the HELLOWORLD program that it calls as a test. I changed it a bit from what I posted to MIDRANGE-L to include some parameters: FQSYSPRT O F 132 PRINTER c *entry plist c parm parm1 32 c parm parm2 32 c parm parm3 15 5 c except print c eval *inlr = *on OQSYSPRT E PRINT O 'Hello World!' O E PRINT O 'Parm1 =' O Parm1 +1 O E PRINT O 'Parm2 =' O Parm2 +1 O E PRINT O 'Parm3 =' O Parm3 L +1 Now comes the fun part... the program that invokes the rexec() API. This program simply downloads the output from the program that it runs into a stream file, and then displays that stream file. I've only tested it at V5R2, but it should work at V5R1 with minor changes. (the rexec() API was introduced in V5R1...) H DFTACTGRP(*NO) ACTGRP(*NEW) H OPTION(*NODEBUGIO: *NOSHOWCPY: *SRCSTMT) H BNDDIR('QC2LE') *------------------------------------------------------------------- * rexec(): send a command to an rexec daemon (like the CL command * RUNRMTCMD with a type of *IP) * * int rexec(char **host, * int port, * char *user, * char *password, * char *command, * int *errorDescriptor); * * host = host to connect to (see note) * * port = TCP port to connect to * * user = null-terminated string containing the userid * * password = null-terminated string containing the password * * command = null-terminated string containing the command * to execute. * * errorDescriptor = descriptor containing the stderr data * (or *OMIT to combine stderr w/stdout) * * NOTE: Host is '**host'. The two asterisks mean we need * to pass a pointer TO A POINTER. The second pointer should * point to the hostname. * * Returns -1 upon error, otherwise a socket descriptor * connected to the stdin/stdout of the command. *------------------------------------------------------------------- D rexec PR 10I 0 extproc('rexec') D host * value D port 10I 0 value D user * value options(*string) D password * value options(*string) D command * value options(*string) D errorDescr 10I 0 options(*omit) *------------------------------------------------------------------- * getservbyname()--Get Port Number for Service Name * * struct servent *getservbyname(char *service_name, * char *protocol_name) * * struct servent { * char *s_name; * char **s_aliases; * int s_port; * char *s_proto; * }; * * This is generally used to look up which port is used for a given * internet service. i.e. if you want to know the port for * TELNET, you'd do x = getservbyname('telnet': 'tcp') *------------------------------------------------------------------- D getservbyname PR * extproc('getservbyname') D service_name * value options(*string) D protocol_nam * value options(*string) D p_servent S * D servent DS based(p_servent) D s_name * D s_aliases * D s_port 10I 0 D s_proto * *------------------------------------------------------------------- * The following prototypes/constants are used for read/writing * from descriptors (either from Sockets, pipes or stream files) *------------------------------------------------------------------- D open PR 10I 0 extproc('open') D path * value options(*string) D oflag 10I 0 value D mode 10U 0 value options(*nopass) D ccsid 10U 0 value options(*nopass) D read PR 10I 0 ExtProc('read') D fildes 10i 0 value D buf * value D nbyte 10U 0 value D write PR 10I 0 extproc('write') D fildes 10I 0 value D buf * value D nbyte 10U 0 value D close PR 10I 0 ExtProc('close') D fildes 10I 0 value * flags for open(): D O_WRONLY C 2 D O_CREAT C 8 D O_TRUNC C 64 D O_CCSID C 32 D O_TEXTDATA C 16777216 D M_RDWR C 438 *------------------------------------------------------------------- * QCMDEXC API *------------------------------------------------------------------- d qcmdexc PR ExtPgm('QCMDEXC') D cmd 32702A const options(*varsize) D len 15P 5 const D IGC 3A const options(*nopass) *------------------------------------------------------------------- * strerror() -- get human-readable error message for errno * * errnum = value of errno to get message for * * returns a null-terminated message string *------------------------------------------------------------------- D strerror PR * ExtProc('strerror') D errnum 10I 0 value *------------------------------------------------------------------- * Local definitions *------------------------------------------------------------------- D errno PR 10I 0 D sock s 10I 0 D stmf s 10I 0 D data s 1024A D msg s 50A D len s 10I 0 D rexec_host s 256A D rexec_host_ptr s * D rexec_port s 10I 0 D parm_host s 32A D parm_user s 32A D parm_password s 32A c *entry plist c parm parm_host c parm parm_user c parm parm_password /free *inlr = *On; if (%parms < 3); dsply ('I need 3 parameters:'); dsply (' -- Host Name'); dsply (' -- User ID for remote host'); msg = '-- Password for remote host'; dsply ' ' ' ' msg; return; endif; // ************************************************ // Get the port number for the 'exec' service // if that fails, fall back to a default of 512 // since that's the most common one. // ************************************************ p_servent = getservbyname('exec': 'tcp'); if (p_servent = *NULL); rexec_port = 512; else; rexec_port = s_port; endif; // ********************************************************** // Populate host name. // // For the host name we must pass a pointer to a pointer, // which means we can't just use options(*string) on the // prototype. // // Instead, we use %str() to store it into a temporary // variable (rexec_host) and then get a pointer to that // space. // ********************************************************** %str(%addr(rexec_host): %size(rexec_host)) = %trimr(parm_host); rexec_host_ptr = %addr(rexec_host); // ********************************************************** // send the rexec() request. (FINALLY!) // // If we *OMIT the last parameter, the STDERR data is sent // in the same socket as the STDOUT data. // ********************************************************** sock = rexec( %addr(rexec_host_ptr) : rexec_port : %trimr(parm_user) : %trimr(parm_password) : 'CALL PGM(HELLOWORLD) PARM(''HELLO'' ''FRIEND'' 42)' : *OMIT ); if (sock < 0); if (errno > 0); msg = 'rexec: ' + %str(strerror(errno)); else; msg = 'rexec: host not found/error logging in'; endif; dsply ' ' ' ' msg; return; endif; // ********************************************************** // open a stream file to store results into // ********************************************************** stmf = open( '/tmp/rexecout.txt' : O_CREAT+O_TRUNC+O_WRONLY+O_CCSID : M_RDWR : 819 ); if (stmf < 0); msg = 'open: ' + %str(strerror(errno)); dsply ' ' ' ' msg; callp close(sock); return; endif; // ********************************************************** // read the results of the rexec command. copy the // results into a stream file. // // NOTE: You don't HAVE to do this. The data returned from // the server will be read, bit by bit, into the // "data" variable (as ASCII data). You could // simply interpret the data directly if you want to. // // (but, IMHO, a stream file is easier) // ********************************************************** dou (len < 1); len = read(sock: %addr(data): %size(data)); if (len > 0); callp write(stmf: %addr(data): len); endif; enddo; // ********************************************************** // disconnect from the remote host and close the // stream file. // ********************************************************** callp close(sock); callp close(stmf); // ********************************************************** // Execute the OS/400 (i5/OS!) command to display the // stream file, then delete it. // ********************************************************** qcmdexc('QSYS/DSPF ''/tmp/rexecout.txt''': 200); qcmdexc('QSYS/RMVLNK ''/tmp/rexecout.txt''': 200); /end-free *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Retrieve the ILE C / UNIX-API error number "errno" * This and strerror() are the only things in this program * that need QC2LE! *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ P errno B D errno PI 10I 0 D sys_errno PR * ExtProc('__errno') D p_errno S * D wwreturn S 10I 0 based(p_errno) C eval p_errno = sys_errno c return wwreturn P E
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.