4.9. Our updated client program

The last several topics have added a lot of improvements to our client program. The result will be something that you could even adapt to your own needs if you wanted an AS/400 program that would fetch web documents.

Here's the new improved sample http client:

    File: SOCKTUT/QRPGLESRC, Member: CLIENTEX2
         H DFTACTGRP(*NO) ACTGRP(*NEW)
         H BNDDIR('QC2LE') BNDDIR('SOCKTUT/SOCKUTIL')
    
         D/copy socktut/qrpglesrc,socket_h
         D/copy socktut/qrpglesrc,errno_h
         D/copy socktut/qrpglesrc,sockutil_h
    
          *********************************************************
          * Definitions needed to make IFS API calls.  Note that
          * these should really be in a separate /copy file!
          *********************************************************
         D O_WRONLY        C                   2
         D O_CREAT         C                   8
         D O_TRUNC         C                   64
         D O_CODEPAGE      C                   8388608
         D open            PR            10I 0 ExtProc('open')
         D  filename                       *   value options(*string)
         D  openflags                    10I 0 value
         D  mode                         10U 0 value options(*nopass)
         D  codepage                     10U 0 value options(*nopass)
         D unlink          PR            10I 0 ExtProc('unlink')
         D   path                          *   Value options(*string)
         D write           PR            10I 0 ExtProc('write')
         D  handle                       10I 0 value
         D  buffer                         *   value
         D  bytes                        10U 0 value
          *********************************************************
          * end of IFS API call definitions
          *********************************************************
    
         D die             PR
         D   peMsg                      256A   const
    
         D cmd             PR                  ExtPgm('QCMDEXC')
         D   command                    200A   const
         D   length                      15P 5 const
    
         D msg             S             50A
         D sock            S             10I 0
         D port            S              5U 0
         D addrlen         S             10I 0
         D ch              S              1A
         D host            s             32A
         D file            s             32A
         D addr            s             10U 0
         D p_Connto        S               *
         D RC              S             10I 0
         D RecBuf          S             50A
         D RecLen          S             10I 0
         D err             S             10I 0
         D fd              S             10I 0
    
         C*************************************************
         C* The user will supply a hostname and file
         C*  name as parameters to our program...
         C*************************************************
         c     *entry        plist
         c                   parm                    host
         c                   parm                    file
    
         c                   eval      *inlr = *on
    
         C*************************************************
         C* what port is the http service located on?
         C*************************************************
         c                   eval      p_servent = getservbyname('http':'tcp')
         c                   if        p_servent = *NULL
         c                   callp     die('Can''t find the HTTP service!')
         c                   return
         c                   endif
    
         c                   eval      port = s_port
    
         C*************************************************
         C* Get the 32-bit network IP address for the host
         C*  that was supplied by the user:
         C*************************************************
         c                   eval      addr = inet_addr(%trim(host))
         c                   if        addr = INADDR_NONE
         c                   eval      p_hostent = gethostbyname(%trim(host))
         c                   if        p_hostent = *NULL
         c                   callp     die('Unable to find that host!')
         c                   return
         c                   endif
         c                   eval      addr = h_addr
         c                   endif
    
         C*************************************************
         C* Create a socket
         C*************************************************
         c                   eval      sock = socket(AF_INET: SOCK_STREAM:
         c                                           IPPROTO_IP)
         c                   if        sock < 0
         c                   callp     die('socket(): ' + %str(strerror(errno)))
         c                   return
         c                   endif
    
         C*************************************************
         C* Create a socket address structure that
         C*   describes the host & port we wanted to
         C*   connect to
         C*************************************************
         c                   eval      addrlen = %size(sockaddr)
         c                   alloc     addrlen       p_connto
    
         c                   eval      p_sockaddr = p_connto
         c                   eval      sin_family = AF_INET
         c                   eval      sin_addr = addr
         c                   eval      sin_port = port
         c                   eval      sin_zero = *ALLx'00'
    
         C*************************************************
         C* Connect to the requested host
         C*************************************************
         C                   if        connect(sock: p_connto: addrlen) < 0
         c                   eval      err = errno
         c                   callp     close(sock)
         c                   callp     die('connect(): '+%str(strerror(err)))
         c                   return
         c                   endif
    
         C*************************************************
         C* Send a request for the file that we'd like
         C* the http server to send us.
         C*
         C* Then we send a blank line to tell it we're
         C* done sending requests, it can process them...
         C*************************************************
         c                   callp     WrLine(sock: 'GET http://' +
         c                               %trim(host) + %trim(file) +
         c                               ' HTTP/1.0')
         c                   callp     WrLine(sock: ' ')
    
         C*************************************************
         C* Get back the server's response codes
         C*
         C* The HTTP server will send it's responses one
         C* by one, then send a blank line to separate
         C* the server responses from the actual data.
         C*************************************************
         c                   dou       recbuf = *blanks
         C                   eval      rc = rdline(sock: %addr(recbuf):
         c                                         %size(recbuf): *On)
         c                   if        rc < 0
         c                   eval      err = errno
         c                   callp     close(sock)
         c                   callp     die('rdline(): '+%str(strerror(err)))
         c                   return
         c                   endif
         c                   enddo
    
         C*************************************************
         C* Open a temporary stream file to put our
         C*   web page data into:
         C*************************************************
         c                   eval      fd = open('/http_tempfile.txt':
         c                                  O_WRONLY+O_TRUNC+O_CREAT+O_CODEPAGE:
         c                                  511: 437)
         c                   if        fd < 0
         c                   eval      err = errno
         c                   callp     close(sock)
         c                   callp     Die('open(): '+%str(strerror(err)))
         c                   return
         c                   endif
    
         C*************************************************
         C* Write returned data to the stream file:
         C*************************************************
         c                   dou       rc < 1
         c                   eval      rc = recv(sock: %addr(recbuf):
         c                                         %size(recbuf): 0)
         c                   if        rc > 0
         c                   callp     write(fd: %addr(recbuf): rc)
         c                   endif
         c                   enddo
    
         C*************************************************
         C*  We're done receiving, do the following:
         C*       1) close the stream file & socket.
         C*       2) display the stream file
         C*       3) unlink (delete) the stream file
         C*       4) end program
         C*************************************************
         c                   callp     close(fd)
         c                   callp     close(sock)
         c                   callp     Cmd('DSPF STMF(''/http_tempfile.txt'')':
         c                                200)
         c                   callp     unlink('/http_tempfile.txt')
    
         c                   return
    
    
          *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
          *  This ends this program abnormally, and sends back an escape.
          *   message explaining the failure.
          *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
         P die             B
         D die             PI
         D   peMsg                      256A   const
    
         D SndPgmMsg       PR                  ExtPgm('QMHSNDPM')
         D   MessageID                    7A   Const
         D   QualMsgF                    20A   Const
         D   MsgData                    256A   Const
         D   MsgDtaLen                   10I 0 Const
         D   MsgType                     10A   Const
         D   CallStkEnt                  10A   Const
         D   CallStkCnt                  10I 0 Const
         D   MessageKey                   4A
         D   ErrorCode                32766A   options(*varsize)
    
         D dsEC            DS
         D  dsECBytesP             1      4I 0 INZ(256)
         D  dsECBytesA             5      8I 0 INZ(0)
         D  dsECMsgID              9     15
         D  dsECReserv            16     16
         D  dsECMsgDta            17    256
    
         D wwMsgLen        S             10I 0
         D wwTheKey        S              4A
    
         c                   eval      wwMsgLen = %len(%trimr(peMsg))
         c                   if        wwMsgLen<1
         c                   return
         c                   endif
    
         c                   callp     SndPgmMsg('CPF9897': 'QCPFMSG   *LIBL':
         c                               peMsg: wwMsgLen: '*ESCAPE':
         c                               '*PGMBDY': 1: wwTheKey: dsEC)
    
         c                   return
         P                 E
    
          /define ERRNO_LOAD_PROCEDURE
          /copy socktut/qrpglesrc,errno_h