× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



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 thread ...


Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

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.