TCP/IP link to the mainframe

Homepage Clovertech Forums Read Only Archives Cloverleaf Cloverleaf TCP/IP link to the mainframe

  • Creator
    Topic
  • #49709
    Jim Lohe
    Participant

    Good morning.   My question is in regards to setting up a new tcp/ip connection to a mainframe application.    Currently all of our interfaces outbound from cloverleaf to the mainframe are LU 6.2.    I am working on creating a TCP/IP connection but one requirement from the mainframe side is that when a message is sent from Cloverleaf, it needs to contain a 4 character CICS transaction ID so that the transaction can be triggered on the mainframe side to receive the message.    

    In the protcol:tcpip option there is a box for data options.   If you click ASCII, it gives you places to type in Length: and Fill:     Is that what that is for?    It seems like I would be sending binary and that the length and fill options are not available for binary.  

    If the above is not the case, how do I tell tcpip what transaction to start?

    Any help is appreciated.  

    Jim Lohe

    BJC Healthcare – St. Louis

Viewing 12 reply threads
  • Author
    Replies
    • #63212
      John Hamilton
      Participant

      I did this exact thing.

      The way I handled it was to write a PDL and use it.

      This was at my old job, I’m sure I have the PDL soemwhere.

      Let me look around for it.

      No that is not what the TCP/IP settings are for.

    • #63213
      Jim Lohe
      Participant

      So…there isn’t something already built in cloverleaf…that helps me!  

      If you find something, I’d appreciate seeing it….it could save me some time.

      Jim

    • #63214
      Jim Kosloskey
      Participant

      Jim,

      Cloverleaf is set up for the standard or typical way of doing TCP/IP encapsulation which is with length encoding.

      The mainframe folks have added an additional requirement due to the way they have their CICS environment configured (LU6.2 is already structured to be CICS aware).

      The PDL functionality of Cloverleaf was set up to try and accomodate individual needs for message encapsulation.

      It appears to me what your mainframe folks want is the CICS transaction code added to the first 4 bytes of the message (the part after the length or beginning encapsulation).  This is not really a part of the communication protocol but rather a part of the message structure.

      If it were me, I would use a Tcl proc to append the transaction ID to the front of the message. I would not use PDL to do this.

      Then I would use either PDL or length encoding to encapsulate the message with the transaction ID as part of the message.

      The outstanding question still is how do they want the message encapsulated? Length encoding or otherwise. They need to tell you that.

      To me the transaction code and encapsulation are two distinctly different issues. One solved with either protocol configuration or PDL and the other with message content.

      Jim Kosloskey

      email: jim.kosloskey@jim-kosloskey.com 29+ years Cloverleaf, 59 years IT - old fart.

    • #63215
      John Hamilton
      Participant

      Question, in reading Jim response.  It dawned on me you may not be dong the same thing we were doing.

      What we did was have an initial message go out to CICS as the Tran ID. Which Identified the CICS transaction we were working with. After that initial message. We no longer need that transaction ID. Unless we lost the connection.

      Are you needing the transaction ID  on every message or just as the first message?  If I recall correctly it could be setup either way. But I’m not a CICS person so that may be incorrect.

    • #63216
      Jim Lohe
      Participant

      Well….that’s what I am trying to figure out….what is it I need to do.

      My systems person seems to be telling me to send a message with the tran id and then after that I won’t need to.     But I am working through what “happens” on the mf side when I send this tran-id message through.

      I do have a good connection to the mainframe…so that’s a start.

    • #63217
      Charlie Bursell
      Participant

      Seems to me you have only partially stated the requirement.  What is the rest?  Will the message be encapsulated or length-encoded?  

      TCP/IP, unlike LU6.2, is not a message based protocol, it is a packet based protocol.  Therefore, you must have some method to delimit a message.  The HL7 standard is MLLP (MLP) encapsulation.

      Once the entire protocol is defined, it should be fairly simple to write a PDL to meet your requirements.

    • #63218
      Jim Kosloskey
      Participant

      Jim,

      Someone from the Mainframe side will need to tell you what they want.

      Outside of SNA I don’t think there is any real standard for this.

      I did Mainframe work for nearly 30 years both as a developer and a systems programmer (CICS, etc.).

      So each application and or systems programmer sets up how they want to know which CICS transaction to start when a message on a communication port is received.

      A common old school method is to have a ‘start of conversation’ message wherein (among other things) the CICS Transaction ID to be started is defined. After that startup then life is back to normal. There is usually also a ‘shut down conversation’ message in this scenario (otherwise there is an excellent chance of losing messages).

      It sounds like this is what is being required of you.

      So you will need to send a different message to ‘start the conversation’ than a normal data message (by the way some protocols require a header indicating a Data message be prepended to the actual data) when you want to start up. This will most likely be accomplished via Tcl.

      You might also need something to indicate you are stopping the conversation. Again most likely Tcl.

      Be aware (and ask the question) some of the old school mainframe guys receive a message and then stop the conversation (they send you a shutdown message) and expect you to restart the conversation.

      One of the other mechanisms used that I have seen is to have a given connection be associated with a specific CICS transaction on the mainframe so that when starting the connection the CICS transaction is started and you don’t need to do anything special. This is a more modern approach and mimics more closely the newer SNA models. But, alas, there are still a lot of mainframe guys doing their thinking in a 20-30 year old world.

      So you can see, if you go outside the SNA LU6.2 world, there are a number of methods which can be used (I have seen others which I have not listed here). Thus it would be very difficult for Quovadx to provide a ‘canned’ facility that woud capably handle the permutations.

      If you would like to chat directly, email me.

      Jim Kosloskey

      email: jim.kosloskey@jim-kosloskey.com 29+ years Cloverleaf, 59 years IT - old fart.

    • #63219
      John Hamilton
      Participant

      Here is the one I have found. This does not really do what you want.

      The difference is that this message encoding only want the FS at the end and not the  which is the standard. This was for the times we were the server as opposed to the client.  

      I have sent an email to my old place of employeement to see if the can send me a copy of where we sent the transaction ID before we sent the normal data.

    • #63220
      Jim Lohe
      Participant

      I am working closely with my mainframe systems person and trying to get a sense of the expected protocol.    All this info is good and helps me wrap my head around the problem.   As soon as I have more info I will be back and may contact some of you directly.

      Thanks all of you for your help.

    • #63221
      Stephan Head
      Participant

      Do you have IP Sockets installed for CICS?  If so, you attach the transid to a port and Cloverleaf communicates with that port.  On the mainframe side, the receiving transid needs to stay “resident” or always “listening”.  The mainframe sending doesn’t.  On CL, that thread would remain “OPENING” until the message is sent.  At least that’s how it works with HealthQuest 2000 from McKesson and the mainframe OS, Z/OS.

    • #63222
      Russ Ross
      Participant

      Here is a working example of one similar if not exactly the same type of interface using TCP/IP to a mainframe from Cloverleaf.

      It is setup as protocol UPOC and invokes a homegrown TCL proc that does the TCP/IP communication to the mainframe.

      First the TCL proc connects to the mainframe which in turn sends back an ACK containing the read and write ports.

      Then it sends the application ID of TRHB on the write port and waits for and ACK back on the read port.

      Once that ACK is received then the message (a DMS document) is sent on the write port and acknowledged on the read port.

      Then the connection is closed until the next message is received.

      The mainframe guys set our TCP/IP stuff as a service similar to telnet so everyone sharse the service on the same ports by doing it this way.

      Here is the UPOC code called upoc_tran_client.tcl

      Code:


      # Begin Module Header ==========================================================
      #
      #——
      # Name:
      #——
      #
      # upoc_tran_client.tcl
      #
      #———
      # Purpose:
      #———
      #
      # Protocol UPOC for moving DMS documents into TRAN via TCP/IP
      #
      #
      #——–
      # Inputs:
      #——–
      #
      # ARGS.IP   – hostname or IP of TRAN server
      # ARGS.PORT – port number on the TRAN server to connect to
      #
      #
      #——-
      # Notes:
      #——-
      #
      #———
      # History:
      #———
      #
      # 199?.??.?? intial version written prior to 1998
      #
      # 2006.12.28 Russ Ross
      #
      #          – added a header section to this proc so the history can be tracked
      #
      #          – send out email notification everytime a DMS document was too large for TRAN
      #            and was truncated in the Xlate which can be determined by checking
      #            the USERDATA metadata keyed entry (DMS_document_too_large_for_TRAN)
      #
      #          – modfied email addresses to use these aliases defined in /etc/aliases
      #
      #            tran_nak
      #            tran_truncation
      #
      # 2007.01.03 Russ Ross
      #          – added date time stamps to all echo statements
      #
      # 2007.01.11 Russ Ross
      #          – added a check to be sure the USERDATA key was found
      #            before invoking the logic to see if the document was truncated
      #
      # End Module Header ============================================================

      proc upoc_tran_client {args} {
        keylget args MODE mode
        keylget args CONTEXT context

        global hostname
        global port
        global trxid
        global trhb_retries
        global msg_retries
        global email_addresses_for_nak
        global email_addresses_for_truncation
        global env HciConnName
        set module “upoc_tran_client v_2007.01.11”

        switch -exact — $mode {
           start {
              keylget args ARGS.IP   hostname
              keylget args ARGS.PORT port
              set trxid TRHB
              set trhb_retries 5
              set msg_retries 1
              set email_addresses_for_nak        “tran_nak”
              set email_addresses_for_truncation “tran_truncation”
              return “”
           }
           run {

              #—————–
              # Retrieve message
              #—————–

              keylget args MSGID msgid
              set msg [msgget $msgid]
              set msg [string trimright $msg ” “]
              set message_rc “”
              set msg_retry_cnt 0
              set conn_flag 0

              while {$msg_retry_cnt < $msg_retries} {            if {$message_rc == "“} {break}

                 #——————————————————————–
                 #  Sleeps one second and retries for 9 times to connect to the server
                 #  If no connection made it breaks out of the loop sends page and
                 #  Shuts down the thread.
                 #——————————————————————–

                 set cntr 0
                 set break_point 0

                 while {$cntr < 9} {               #---------------------------------------               # Set up file handles for read and write               #---------------------------------------               echo n[exec date] ($module / $HciConnName): CONNECTING to $hostname on port $port               set code [catch {set file_hd [server_open $hostname $port]}]               if [cequal $code 0] {break}               incr cntr               sleep 1               echo n[exec date] ($module / $HciConnName): Alert Number of Tries $cntr to connect to $hostname               if [cequal $cntr 9] {                  set break_point 1               }            }            if [cequal $break_point 1] {               set message_rc "could not connect to $hostname"               echo n[exec date] ($module / $HciConnName): $message_rc               set conn_flag 1               break            }            set fd_gets [lindex $file_hd 0]            set fd_puts [lindex $file_hd 1]            #-----------------------------------------            # Send TRHB to MVS and get Acknowledgement            #-----------------------------------------            echo n[exec date] ($module / $HciConnName): WRITING $trxid to SOCKET $fd_puts            puts $fd_puts $trxid            flush $fd_puts            echo n[exec date] ($module / $HciConnName): READING SOCKET $fd_gets            set ret_val [gets $fd_gets]            echo n[exec date] ($module / $HciConnName): TRXIDRETVAL $ret_val            echo n[exec date] ($module / $HciConnName): "--------------------------------------------------"            #-----------------------------------------            # Check for TRHB ACK.  If not one, resend.            #-----------------------------------------            set trhb_retry_count 0            while {$ret_val != "” && $trhb_retry_count < $trhb_retries} {               echo n[exec date] ($module / $HciConnName): RETURNVAL $ret_val               echo n[exec date] ($module / $HciConnName): RESENDING $trxid               puts $fd_puts $trxid               flush $fd_puts               set ret_val [gets $fd_gets]               incr trhb_retry_count            }            #------------------------------------------------------------            # ACK received.  Write message to MVS and get Acknowledgement            #------------------------------------------------------------            if {$ret_val == "“} {
                    echo n[exec date] ($module / $HciConnName): WRITING message to SOCKET $fd_puts
                    puts $fd_puts $msg
                    echo n[exec date] ($module / $HciConnName): FLUSHING message from SOCKET $fd_puts
                    flush $fd_puts
                    echo n[exec date] ($module / $HciConnName): READING message from SOCKET $fd_gets
                    set message_rc [gets $fd_gets]
                    echo n[exec date] ($module / $HciConnName): MESSAGERETVAL $message_rc
                    echo n[exec date] ($module / $HciConnName): “————————————————–”
                 }

                 close $fd_puts
                 close $fd_gets
                 incr msg_retry_cnt
              }

              if {$message_rc != “” || $conn_flag} {

                 #—————————————————————————–
                 # if we ever get here, it means the message got Naked 5 times
                 # or we were unable to connect to the server so
                 # save message to a file, turn off alerts, send email, and shutdown the thread
                 #—————————————————————————–

                 echo n[exec date] ($module / $HciConnName): MAX RETRIES DONE

                 #————————————————–
                 # build file names as julian date.counter.extension
                 #————————————————–

                 set saveDir $HciConnName
                 append saveDir “_NAKS/”
                 set julian [fmtclock [getclock] %Y%j]
                 set fileCounter [format %05d [CtrNextValue “.test_tran_client.$HciConnName”]]
                 set NakFileSpec $saveDir$julian.$fileCounter.nak
                 set MsgFileSpec $saveDir$julian.$fileCounter.msg

                 #———————————————–
                 # create the save directories if they dont exist
                 #———————————————–

                 if {![file exists $saveDir]} {
                    echo n[exec date] ($module / $HciConnName): creating $saveDir
                    exec mkdir $saveDir
                 }

                 #—————————————————
                 # save the Nak message in a file with extension .nak
                 #—————————————————

                 set Nakfd [open $NakFileSpec a+]
                 puts $Nakfd $message_rc
                 close $Nakfd

                 #—————————————————-
                 # save the original msg in a file with extension .msg
                 #—————————————————-

                 set Msgfd [open $MsgFileSpec a+]
                 puts $Msgfd $msg
                 close $Msgfd

                 #——————————–
                 # turn off alerts for this thread
                 #——————————–

                 # Next line of code uncommented out by Russ Ross 2001.08.28

                 system “touch ../../../Alerts/$HciConnName.off”

                 #——————————————————————-
                 # append a time stamped entry to the alerts log file for this thread
                 #——————————————————————-

                 set logfile “../../../Alerts/$HciConnName.log”
                 set logfh [open $logfile a+]
                 set ts [fmtclock [getclock] “%a %b %d %Y %r “]
                 set email_subject_for_nak “shutdown $HciConnName because $message_rc”
                 puts $logfh “$ts($email_subject_for_nak) ($email_addresses_for_nak)”
                 close $logfh

                 #——————————————————–
                 # send email notification that the thread has been NACKed
                 #——————————————————–

                 system “echo “Subject: $email_subject_for_nak\n.” | sendmail $email_addresses_for_nak”
                 echo n[exec date] ($module / $HciConnName): recieved 5 Naks for the following message,
                 stoping thread!!! n$msg

                 #————
                 # stop thread
                 #————

                 # Next 3 lines of code uncommented out by Russ Ross 2001.08.28

                 set process [file tail [pwd]]
                 echo n[exec date] ($module / $HciConnName): Stopping the Thread: $HciConnName
                 system “hcicmd -p $process -c “$HciConnName pstop””
              }

              #—————————————————————————-
              # at this point TRAN has received the document and sent back an ACK
              #
              # send out email notification everytime a DMS document was too large for TRAN
              # and was truncated in the Xlate which can be determined by checking
              # the USERDATA metadata keyed entry (DMS_document_too_large_for_TRAN)
              #—————————————————————————-

              set datum_list [datlist]
              set USERDATA_metadata [msgmetaget $msgid “USERDATA”]
              set USERDATA_key_was_found [keylget USERDATA_metadata DMS_document_too_large_for_TRAN USERDATA_metadata_value]
              if {$USERDATA_key_was_found} {
                 if { [string match -nocase $USERDATA_metadata_value “Y”] } {

                    set document_number “GRM_problem”
                    if {![catch {set ghd [grmcreate -msg $msgid frl tran_dms]} cerr]} {
                       if {![catch {set fhd [lindex [grmfetch $ghd txa12_udn_document] 0]}]} {
                          set document_number [datget $fhd VALUE]
                       } else { echo n[exec date] ($module / $HciConnName): GRM fetch problem!!!n$cerrn }
                    } else { echo n[exec date] ($module / $HciConnName): GRM create problem!!!n$cerrn }

                    set email_subject_for_truncation “DMS document ($document_number) was too large for TRAN and has been truncated!!!”
                    system “echo “Subject: $email_subject_for_truncation\n.” | sendmail $email_addresses_for_truncation”
                    echo n[exec date] ($module / $HciConnName): $email_subject_for_truncation
                    echo n[exec date] ($module / $HciConnName): below is a msgdump for debugging and on-call support purposesn
                    msgdump $msgid
                    if {[info exists ghd]} {grmdestroy $ghd}
                 }
              }
              hcidatlistreset $datum_list

              #————————————————
              # CONTIUE message so SMAT will be able to save it
              #————————————————

              echo n[exec date] ($module / $HciConnName): “ABOUT TO CONTINUE message to SMAT”
              return “{CONTINUE $msgid}”

           }

      shutdown {
         # Doing some clean-up work
      }
           default {
              echo n[exec date] ($module / $HciConnName): Invalid Mode $mode
           }
        }
      }

      Here is the upoc code called upoc_nothing.tcl

      Code:


      proc upoc_nothing { args } {
         keylget args MODE mode               ;# Fetch mode
         global HciConnName

         set dispList {} ;# Nothing to return

         switch -exact — $mode {
             start {
                 # do nothing
             }

             run {
                 # do nothing
             }

             time {
                 # do nothing
             }

      shutdown {
                 # do nothing
      }

             default {
         error “Unknown mode ‘$mode’ in tps_numfile_ob”
             }
         }

         return $dispList
      }

      There is a known bug in our upoc_tran_client.tcl proc that hangs forever if no ACK is received back after sending the TRHB application ID to the mainframe.

      Fortunately this rarely happens and is why I still haven’t coded the fix.

      I have an example of a solution that use the commands

      after

      vwait

      from a TCL class I took that can be used to fix my hung while waiting for ACK problem.

      Here is that sample TCL code from that class to illustrate how I can use these commands to allow my UPOC to invoke timeout logic if an ACK never comes back from the mainframe.

      The sample TCL proc below is call gets.tcl

      Code:


      proc connection {mysock ip port} {
        global sock
        set sock $mysock
      }
      socket -server connection 8888

      proc newgets {sock {seconds 10}} {
        global responded _data

        set responded 0
        after [expr $seconds * 1000] set done 1
        fileevent $sock readable “gets $sock _data; set responded 1; set done 1”
        vwait done

        fileevent $sock readable {}
        after abort {set done 1}

        if {$responded} {
      return $_data
        } else {
      error “timeout on read of socket ‘$sock'”
        }
      }

      Here is an example of what is written to the process log file by upoc_tran_client.tcl to help you understand the TCL proc:

      Code:


      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): CONNECTING to 143.111.65.11 on port 3004

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): WRITING TRHB to SOCKET sock32

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): READING SOCKET sock31

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): TRXIDRETVAL

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): ————————————————–

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): WRITING message to SOCKET sock32

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): FLUSHING message from SOCKET sock32

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): READING message from SOCKET sock31

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): MESSAGERETVAL

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): ————————————————–

      Thu Dec 20 17:53:22 CST 2007 (upoc_tran_client v_2007.01.11 / ob_tran_3004): ABOUT TO CONTINUE message to SMAT

      Be aware that when you specify protocol UPOC you get ultimate flexibility but also assume all the responisbility.

      Here are screen shot of the NetConfig to help illustrate how this proc gets invoked by cloverleaf.

      [/code]

      Russ Ross
      RussRoss318@gmail.com

    • #63223
      Russ Ross
      Participant

      FYI –  since the upoc_tran_client.tcl proc in my previous post has a sleep in it, be sure to put it in its own process.

      Russ Ross
      RussRoss318@gmail.com

    • #63224
      John Hamilton
      Participant

      Ok I have the PDL here you go.

      A little description on how we set this up where I was.

      The HIS system was setup as a multi-server.

      When we called them to send data the first message established a connection to their system. Then within HIS it established a LU6.2 connetions between their TCP/IP region LU6.2 region.

      We had to send a “Conversion start” that told them what LU6.2 transaction to use.  Then we just sent data with a standard mlp_tcp encapulation

      Clear as Mud I’m sure. If you need any help just call or email me.

Viewing 12 reply threads
  • The forum ‘Cloverleaf’ is closed to new topics and replies.

Forum Statistics

Registered Users
5,117
Forums
28
Topics
9,292
Replies
34,435
Topic Tags
286
Empty Topic Tags
10