› Clovertech Forums › Read Only Archives › Cloverleaf › Cloverleaf › TCP/IP link to the mainframe
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
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.
If you find something, I’d appreciate seeing it….it could save me some time.
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.
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.
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.
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.
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.
The difference is that this message encoding only want the FS at the end and not the
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.
Thanks all of you for your help.
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
# 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 == "
#——————————————————————–
# 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 != "
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 != “
#—————————————————————————–
# 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
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
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:
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
Russ Ross
RussRoss318@gmail.com
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.