- HLCSTCP1 ;SFIRMFO/RSD - BI-DIRECTIONAL TCP ;09/13/2006
- ;;1.6;HEALTH LEVEL SEVEN;**19,43,57,64,71,133**;JUL 17,1995;Build 13
- ;Per VHA Directive 2004-038, this routine should not be modified.
- ;Receiver
- ;connection is initiated by sender and listener accepts connection
- ;and calls this routine
- ;
- N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP1"
- N HLMIEN,HLASTMSG
- D MON^HLCSTCP("Open")
- K ^TMP("HLCSTCP",$J,0)
- S HLMIEN=0,HLASTMSG=""
- F D Q:$$STOP^HLCSTCP I 'HLMIEN D MON^HLCSTCP("Idle") H 3
- . S HLMIEN=$$READ
- . Q:'HLMIEN
- . D PROCESS
- Q
- ;
- PROCESS ;check message and reply
- ;HLDP=LL in 870, update monitor, received msg.
- N HLTCP,HLTCPI,HLTCPO
- S HLTCP="",HLTCPO=HLDP,HLTCPI=+HLMIEN
- ;update monitor, msg. received
- D LLCNT^HLCSTCP(HLDP,1)
- D NEW^HLTP3(HLMIEN)
- ;update monitor, msg. processed
- D LLCNT^HLCSTCP(HLDP,2)
- Q
- ;
- READ() ;read 1 message, returns ien in 773^ien in 772 for message
- D MON^HLCSTCP("Reading")
- N HLDB,HLDT,HLDEND,HLACKWT,HLDSTRT,HLHDR,HLIND1,HLINE,HLMSG,HLRDOUT,HLRS,HLX,X
- ;HLDSTRT=start char., HLDEND=end char., HLRS=record seperator
- S HLDSTRT=$C(11),HLDEND=$C(28),HLRS=$C(13)
- ;HLRDOUT=exit read loop, HLINE=line count, HLIND1=ien 773^ien 772
- ;HLHDR=have a header, ^TMP(...)=excess from last read, HLACKWT=wait for ack
- S (HLRDOUT,HLINE,HLIND1,HLHDR)=0,HLX=$G(^TMP("HLCSTCP",$J,0)),HLACKWT=HLDBACK
- K ^TMP("HLCSTCP",$J,0)
- F D RDBLK Q:HLRDOUT
- ;save any excess for next time
- S:$L(HLX) ^TMP("HLCSTCP",$J,0)=HLX
- I +HLIND1,'$P(HLIND1,U,3) D DELMSG(HLIND1) S HLIND1=0
- Q HLIND1
- ;
- RDBLK S HLDB=HLDBSIZE-$L(HLX)
- U IO R X#HLDB:HLDREAD
- ;switch to null device if opened to prevent 'leakage'
- I $G(IO(0))'="",$G(IO(0))'=IO U IO(0)
- ; timedout, check ack timeout, clean up
- I '$T,X="",HLX="" S HLACKWT=HLACKWT-HLDREAD D:HLACKWT<0&'HLHDR CLEAN Q
- ;data stream: <sb>dddd<cr><eb><cr>
- ;add incoming line to what wasn't processed in last read
- S HLX=$G(HLX)_X
- ; look for segment= <CR>
- F Q:HLX'[HLRS D Q:HLRDOUT
- . ; Get the first piece, save the rest of the line
- . S HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLRS),HLX=$P(HLX,HLRS,2,999)
- . ; check for start block, Quit if no ien
- . I HLMSG(HLINE,0)[HLDSTRT!HLHDR D Q
- .. D:HLMSG(HLINE,0)[HLDSTRT
- ... S X=$L(HLMSG(HLINE,0),HLDSTRT)
- ... S:X>2 HLMSG(HLINE,0)=HLDSTRT_$P(HLMSG(HLINE,0),HLDSTRT,X)
- ... S HLMSG(HLINE,0)=$P(HLMSG(HLINE,0),HLDSTRT,2)
- ... D RESET:(HLINE>1)
- .. ;ping message
- .. I $E(HLMSG(1,0),1,9)="MSH^PING^" D PING Q
- .. ; get next ien to store
- .. D MIEN
- .. K HLMSG
- .. S (HLINE,HLHDR)=0
- . ; check for end block; HLMSG(HLINE) = <eb><cr>
- . I HLMSG(HLINE,0)[HLDEND D
- .. ;no msg. ien
- .. Q:'HLIND1
- .. ; Kill just the last line
- .. K HLMSG(HLINE,0) S HLINE=HLINE-1
- .. ; move into 772
- .. D SAVE(.HLMSG,"^HL(772,"_+$P(HLIND1,U,2)_",""IN"")")
- .. ;mark that end block has been received
- .. ;HLIND1=ien in 773^ien in 772^1 if end block was received
- .. S $P(HLIND1,U,3)=1
- .. ;reset variables for next message
- .. D CLEAN
- . ;add blank line for carriage return
- . I HLINE'=0,HLMSG(HLINE,0)]"" S HLINE=HLINE+1,HLMSG(HLINE,0)=""
- Q:HLRDOUT
- ;If the line is long and no <CR> move it into the array.
- I ($L(HLX)=HLDBSIZE),(HLX'[HLRS),(HLX'[HLDEND),(HLX'[HLDSTRT) D Q
- . S HLINE=HLINE+1,HLMSG(HLINE,0)=HLX,HLX=""
- ;have start block but no record seperator
- I HLX[HLDSTRT D Q
- . ;check for more than 1 start block
- . S X=$L(HLX,HLDSTRT) S:X>2 HLX=HLDSTRT_$P(HLX,HLDSTRT,X)
- . S:$L($P(HLX,HLDSTRT,2))>8 HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLDSTRT,2),HLX="",HLHDR=1
- . D RESET:(HLHDR&(HLINE>1))
- ;if no ien, then we don't have start block, reset
- I 'HLIND1 D CLEAN Q
- ; big message-merge from local to global every 100 lines
- I (HLINE-$O(HLMSG(0)))>100 D
- . M ^HL(772,+$P(HLIND1,U,2),"IN")=HLMSG
- . ; reset working array
- . K HLMSG
- Q
- ;
- SAVE(SRC,DEST) ;save into global & set top node
- ;SRC=source array (passed by ref.), DEST=destination global
- M @DEST=SRC
- S @DEST@(0)="^^"_HLINE_"^"_HLINE_"^"_DT_"^"
- Q
- ;
- DELMSG(HLMAMT) ;delete message from Message Administration/Message Text files.
- N DIK,DA
- S DA=+HLMAMT,DIK="^HLMA("
- D ^DIK
- S DA=$P(HLMAMT,U,2),DIK="^HL(772,"
- D ^DIK
- Q
- MIEN ; sets HLIND1=ien in 773^ien in 772 for message
- N HLMID,X
- I HLIND1 D
- . S:'$G(^HLMA(+HLIND1,0)) HLIND1=0
- . S:'$G(^HL(772,+$P(HLIND1,U,2),0)) HLIND1=0
- ;msg. id is 10th of MSH & 11th for BSH or FSH
- S X=10+($E(HLMSG(1,0),1,3)'="MSH"),HLMID=$$PMSH(.HLMSG,X)
- ;if HLIND1 is set, kill old message, use HLIND1 for new
- ;message, it means we never got end block for 1st msg.
- I HLIND1 D Q
- . ;get pointer to 772, kill header
- . K ^HLMA(+HLIND1,"MSH")
- . I $D(^HL(772,+$P(HLIND1,U,2),"IN")) K ^("IN")
- . S X=$$MAID^HLTF(+HLIND1,HLMID)
- . D SAVE(.HLMSG,"^HLMA("_+HLIND1_",""MSH"")")
- . S:$P(HLIND1,U,3) $P(HLIND1,U,3)=""
- D TCP^HLTF(.HLMID,.X,.HLDT)
- I 'X D Q
- . ;error - record and reset array
- . ;killing HLLSTN will allow MON^HLCSTCP to work with multi-server
- . D CLEAN K HLLSTN
- . ;error 100=LLP Could not Enqueue the Message, reset array
- . D MONITOR^HLCSDR2(100,19,HLDP),MON^HLCSTCP("ERROR") H 30
- ;HLIND1=ien in 773^ien in 772
- S HLIND1=X_U_+$G(^HLMA(X,0))
- ;save MSH into 773
- D SAVE(.HLMSG,"^HLMA("_+HLIND1_",""MSH"")")
- Q
- ;
- PMSH(MSH,P) ;get piece P from MSH array (passed by ref.)
- N FS,I,L,L1,L2,X,Y
- S FS=$E(MSH(1,0),4),(L2,Y)=0,X=""
- F I=1:1 S L1=$L($G(MSH(I,0)),FS),L=L1+Y-1 D Q:$L(X)!'$D(MSH(I,0))
- . S:L1=1 L=L+1
- . S:P'>L X=$P($G(MSH(I-1,0)),FS,P-L2)_$P($G(MSH(I,0)),FS,(P-Y))
- . S L2=Y,Y=L
- Q X
- ;
- PING ;process PING message
- S X=HLMSG(1,0)
- I X[HLDEND U IO W X,! I $G(IO(0))'="",$G(IO(0))'=IO U IO(0) ;switch to null device if opened to prevent 'leakage'
- ;
- CLEAN ;reset var. for next message
- K HLMSG
- S HLINE=0,HLRDOUT=1
- Q
- ;
- ERROR ; Error trap for disconnect error and return back to the read loop.
- S $ETRAP="D UNWIND^%ZTER"
- I $$EC^%ZOSV["READ"!($$EC^%ZOSV["NOTOPEN")!($$EC^%ZOSV["DEVNOTOPN") D UNWIND^%ZTER Q
- I $$EC^%ZOSV["WRITE" D CC("Wr-err") D UNWIND^%ZTER Q
- S HLCSOUT=1 D ^%ZTER,CC("Error")
- D UNWIND^%ZTER
- Q
- ;
- CC(X) ;cleanup and close
- D MON^HLCSTCP(X)
- H 2
- Q
- RESET ;reset info as a result of no end block
- N %
- S HLMSG(1,0)=HLMSG(HLINE,0)
- F %=2:1:HLINE K HLMSG(%,0)
- S HLINE=1
- Q
- HLCSTCP1 ;SFIRMFO/RSD - BI-DIRECTIONAL TCP ;09/13/2006
- +1 ;;1.6;HEALTH LEVEL SEVEN;**19,43,57,64,71,133**;JUL 17,1995;Build 13
- +2 ;Per VHA Directive 2004-038, this routine should not be modified.
- +3 ;Receiver
- +4 ;connection is initiated by sender and listener accepts connection
- +5 ;and calls this routine
- +6 ;
- +7 NEW $ETRAP,$ESTACK
- SET $ETRAP="D ERROR^HLCSTCP1"
- +8 NEW HLMIEN,HLASTMSG
- +9 DO MON^HLCSTCP("Open")
- +10 KILL ^TMP("HLCSTCP",$JOB,0)
- +11 SET HLMIEN=0
- SET HLASTMSG=""
- +12 FOR
- Begin DoDot:1
- +13 SET HLMIEN=$$READ
- +14 IF 'HLMIEN
- QUIT
- +15 DO PROCESS
- End DoDot:1
- IF $$STOP^HLCSTCP
- QUIT
- IF 'HLMIEN
- DO MON^HLCSTCP("Idle")
- HANG 3
- +16 QUIT
- +17 ;
- PROCESS ;check message and reply
- +1 ;HLDP=LL in 870, update monitor, received msg.
- +2 NEW HLTCP,HLTCPI,HLTCPO
- +3 SET HLTCP=""
- SET HLTCPO=HLDP
- SET HLTCPI=+HLMIEN
- +4 ;update monitor, msg. received
- +5 DO LLCNT^HLCSTCP(HLDP,1)
- +6 DO NEW^HLTP3(HLMIEN)
- +7 ;update monitor, msg. processed
- +8 DO LLCNT^HLCSTCP(HLDP,2)
- +9 QUIT
- +10 ;
- READ() ;read 1 message, returns ien in 773^ien in 772 for message
- +1 DO MON^HLCSTCP("Reading")
- +2 NEW HLDB,HLDT,HLDEND,HLACKWT,HLDSTRT,HLHDR,HLIND1,HLINE,HLMSG,HLRDOUT,HLRS,HLX,X
- +3 ;HLDSTRT=start char., HLDEND=end char., HLRS=record seperator
- +4 SET HLDSTRT=$CHAR(11)
- SET HLDEND=$CHAR(28)
- SET HLRS=$CHAR(13)
- +5 ;HLRDOUT=exit read loop, HLINE=line count, HLIND1=ien 773^ien 772
- +6 ;HLHDR=have a header, ^TMP(...)=excess from last read, HLACKWT=wait for ack
- +7 SET (HLRDOUT,HLINE,HLIND1,HLHDR)=0
- SET HLX=$GET(^TMP("HLCSTCP",$JOB,0))
- SET HLACKWT=HLDBACK
- +8 KILL ^TMP("HLCSTCP",$JOB,0)
- +9 FOR
- DO RDBLK
- IF HLRDOUT
- QUIT
- +10 ;save any excess for next time
- +11 IF $LENGTH(HLX)
- SET ^TMP("HLCSTCP",$JOB,0)=HLX
- +12 IF +HLIND1
- IF '$PIECE(HLIND1,U,3)
- DO DELMSG(HLIND1)
- SET HLIND1=0
- +13 QUIT HLIND1
- +14 ;
- RDBLK SET HLDB=HLDBSIZE-$LENGTH(HLX)
- +1 USE IO
- READ X#HLDB:HLDREAD
- +2 ;switch to null device if opened to prevent 'leakage'
- +3 IF $GET(IO(0))'=""
- IF $GET(IO(0))'=IO
- USE IO(0)
- +4 ; timedout, check ack timeout, clean up
- +5 IF '$TEST
- IF X=""
- IF HLX=""
- SET HLACKWT=HLACKWT-HLDREAD
- IF HLACKWT<0&'HLHDR
- DO CLEAN
- QUIT
- +6 ;data stream: <sb>dddd<cr><eb><cr>
- +7 ;add incoming line to what wasn't processed in last read
- +8 SET HLX=$GET(HLX)_X
- +9 ; look for segment= <CR>
- +10 FOR
- IF HLX'[HLRS
- QUIT
- Begin DoDot:1
- +11 ; Get the first piece, save the rest of the line
- +12 SET HLINE=HLINE+1
- SET HLMSG(HLINE,0)=$PIECE(HLX,HLRS)
- SET HLX=$PIECE(HLX,HLRS,2,999)
- +13 ; check for start block, Quit if no ien
- +14 IF HLMSG(HLINE,0)[HLDSTRT!HLHDR
- Begin DoDot:2
- +15 IF HLMSG(HLINE,0)[HLDSTRT
- Begin DoDot:3
- +16 SET X=$LENGTH(HLMSG(HLINE,0),HLDSTRT)
- +17 IF X>2
- SET HLMSG(HLINE,0)=HLDSTRT_$PIECE(HLMSG(HLINE,0),HLDSTRT,X)
- +18 SET HLMSG(HLINE,0)=$PIECE(HLMSG(HLINE,0),HLDSTRT,2)
- +19 IF (HLINE>1)
- DO RESET
- End DoDot:3
- +20 ;ping message
- +21 IF $EXTRACT(HLMSG(1,0),1,9)="MSH^PING^"
- DO PING
- QUIT
- +22 ; get next ien to store
- +23 DO MIEN
- +24 KILL HLMSG
- +25 SET (HLINE,HLHDR)=0
- End DoDot:2
- QUIT
- +26 ; check for end block; HLMSG(HLINE) = <eb><cr>
- +27 IF HLMSG(HLINE,0)[HLDEND
- Begin DoDot:2
- +28 ;no msg. ien
- +29 IF 'HLIND1
- QUIT
- +30 ; Kill just the last line
- +31 KILL HLMSG(HLINE,0)
- SET HLINE=HLINE-1
- +32 ; move into 772
- +33 DO SAVE(.HLMSG,"^HL(772,"_+$PIECE(HLIND1,U,2)_",""IN"")")
- +34 ;mark that end block has been received
- +35 ;HLIND1=ien in 773^ien in 772^1 if end block was received
- +36 SET $PIECE(HLIND1,U,3)=1
- +37 ;reset variables for next message
- +38 DO CLEAN
- End DoDot:2
- +39 ;add blank line for carriage return
- +40 IF HLINE'=0
- IF HLMSG(HLINE,0)]""
- SET HLINE=HLINE+1
- SET HLMSG(HLINE,0)=""
- End DoDot:1
- IF HLRDOUT
- QUIT
- +41 IF HLRDOUT
- QUIT
- +42 ;If the line is long and no <CR> move it into the array.
- +43 IF ($LENGTH(HLX)=HLDBSIZE)
- IF (HLX'[HLRS)
- IF (HLX'[HLDEND)
- IF (HLX'[HLDSTRT)
- Begin DoDot:1
- +44 SET HLINE=HLINE+1
- SET HLMSG(HLINE,0)=HLX
- SET HLX=""
- End DoDot:1
- QUIT
- +45 ;have start block but no record seperator
- +46 IF HLX[HLDSTRT
- Begin DoDot:1
- +47 ;check for more than 1 start block
- +48 SET X=$LENGTH(HLX,HLDSTRT)
- IF X>2
- SET HLX=HLDSTRT_$PIECE(HLX,HLDSTRT,X)
- +49 IF $LENGTH($PIECE(HLX,HLDSTRT,2))>8
- SET HLINE=HLINE+1
- SET HLMSG(HLINE,0)=$PIECE(HLX,HLDSTRT,2)
- SET HLX=""
- SET HLHDR=1
- +50 IF (HLHDR&(HLINE>1))
- DO RESET
- End DoDot:1
- QUIT
- +51 ;if no ien, then we don't have start block, reset
- +52 IF 'HLIND1
- DO CLEAN
- QUIT
- +53 ; big message-merge from local to global every 100 lines
- +54 IF (HLINE-$ORDER(HLMSG(0)))>100
- Begin DoDot:1
- +55 MERGE ^HL(772,+$PIECE(HLIND1,U,2),"IN")=HLMSG
- +56 ; reset working array
- +57 KILL HLMSG
- End DoDot:1
- +58 QUIT
- +59 ;
- SAVE(SRC,DEST) ;save into global & set top node
- +1 ;SRC=source array (passed by ref.), DEST=destination global
- +2 MERGE @DEST=SRC
- +3 SET @DEST@(0)="^^"_HLINE_"^"_HLINE_"^"_DT_"^"
- +4 QUIT
- +5 ;
- DELMSG(HLMAMT) ;delete message from Message Administration/Message Text files.
- +1 NEW DIK,DA
- +2 SET DA=+HLMAMT
- SET DIK="^HLMA("
- +3 DO ^DIK
- +4 SET DA=$PIECE(HLMAMT,U,2)
- SET DIK="^HL(772,"
- +5 DO ^DIK
- +6 QUIT
- MIEN ; sets HLIND1=ien in 773^ien in 772 for message
- +1 NEW HLMID,X
- +2 IF HLIND1
- Begin DoDot:1
- +3 IF '$GET(^HLMA(+HLIND1,0))
- SET HLIND1=0
- +4 IF '$GET(^HL(772,+$PIECE(HLIND1,U,2),0))
- SET HLIND1=0
- End DoDot:1
- +5 ;msg. id is 10th of MSH & 11th for BSH or FSH
- +6 SET X=10+($EXTRACT(HLMSG(1,0),1,3)'="MSH")
- SET HLMID=$$PMSH(.HLMSG,X)
- +7 ;if HLIND1 is set, kill old message, use HLIND1 for new
- +8 ;message, it means we never got end block for 1st msg.
- +9 IF HLIND1
- Begin DoDot:1
- +10 ;get pointer to 772, kill header
- +11 KILL ^HLMA(+HLIND1,"MSH")
- +12 IF $DATA(^HL(772,+$PIECE(HLIND1,U,2),"IN"))
- KILL ^("IN")
- +13 SET X=$$MAID^HLTF(+HLIND1,HLMID)
- +14 DO SAVE(.HLMSG,"^HLMA("_+HLIND1_",""MSH"")")
- +15 IF $PIECE(HLIND1,U,3)
- SET $PIECE(HLIND1,U,3)=""
- End DoDot:1
- QUIT
- +16 DO TCP^HLTF(.HLMID,.X,.HLDT)
- +17 IF 'X
- Begin DoDot:1
- +18 ;error - record and reset array
- +19 ;killing HLLSTN will allow MON^HLCSTCP to work with multi-server
- +20 DO CLEAN
- KILL HLLSTN
- +21 ;error 100=LLP Could not Enqueue the Message, reset array
- +22 DO MONITOR^HLCSDR2(100,19,HLDP)
- DO MON^HLCSTCP("ERROR")
- HANG 30
- End DoDot:1
- QUIT
- +23 ;HLIND1=ien in 773^ien in 772
- +24 SET HLIND1=X_U_+$GET(^HLMA(X,0))
- +25 ;save MSH into 773
- +26 DO SAVE(.HLMSG,"^HLMA("_+HLIND1_",""MSH"")")
- +27 QUIT
- +28 ;
- PMSH(MSH,P) ;get piece P from MSH array (passed by ref.)
- +1 NEW FS,I,L,L1,L2,X,Y
- +2 SET FS=$EXTRACT(MSH(1,0),4)
- SET (L2,Y)=0
- SET X=""
- +3 FOR I=1:1
- SET L1=$LENGTH($GET(MSH(I,0)),FS)
- SET L=L1+Y-1
- Begin DoDot:1
- +4 IF L1=1
- SET L=L+1
- +5 IF P'>L
- SET X=$PIECE($GET(MSH(I-1,0)),FS,P-L2)_$PIECE($GET(MSH(I,0)),FS,(P-Y))
- +6 SET L2=Y
- SET Y=L
- End DoDot:1
- IF $LENGTH(X)!'$DATA(MSH(I,0))
- QUIT
- +7 QUIT X
- +8 ;
- PING ;process PING message
- +1 SET X=HLMSG(1,0)
- +2 ;switch to null device if opened to prevent 'leakage'
- IF X[HLDEND
- USE IO
- WRITE X,!
- IF $GET(IO(0))'=""
- IF $GET(IO(0))'=IO
- USE IO(0)
- +3 ;
- CLEAN ;reset var. for next message
- +1 KILL HLMSG
- +2 SET HLINE=0
- SET HLRDOUT=1
- +3 QUIT
- +4 ;
- ERROR ; Error trap for disconnect error and return back to the read loop.
- +1 SET $ETRAP="D UNWIND^%ZTER"
- +2 IF $$EC^%ZOSV["READ"!($$EC^%ZOSV["NOTOPEN")!($$EC^%ZOSV["DEVNOTOPN")
- DO UNWIND^%ZTER
- QUIT
- +3 IF $$EC^%ZOSV["WRITE"
- DO CC("Wr-err")
- DO UNWIND^%ZTER
- QUIT
- +4 SET HLCSOUT=1
- DO ^%ZTER
- DO CC("Error")
- +5 DO UNWIND^%ZTER
- +6 QUIT
- +7 ;
- CC(X) ;cleanup and close
- +1 DO MON^HLCSTCP(X)
- +2 HANG 2
- +3 QUIT
- RESET ;reset info as a result of no end block
- +1 NEW %
- +2 SET HLMSG(1,0)=HLMSG(HLINE,0)
- +3 FOR %=2:1:HLINE
- KILL HLMSG(%,0)
- +4 SET HLINE=1
- +5 QUIT