HLOTCP ;ALB/CJM- TCP/IP I/O - 10/4/94 1pm ;03/01/2011
;;1.6;HEALTH LEVEL SEVEN;**126,131,134,137,138,139,146,153**;Oct 13, 1995;Build 11
;Per VHA Directive 2004-038, this routine should not be modified.
;
OPEN(HLCSTATE,LOGICAL) ;
;This may be called either in the context of a client or a server.
;For the server, there are 3 situations:
; 1) The server is not concurrent. In this case the TCP device should be opened.
; 2) The server is concurrent, but this process was spawned by the OS
; (via a VMS TCP Service) In this case, the device should be opened
; via the LOGICAL that was passed in.
; 3) The server is concurrent, but this process was spawned by the
; TaskMan multi-listener. In this case TaskMan already opened the
; device. This case can be determined by the absence of the LOGICAL
; input parameter.
;
N IP,PORT,DNSFLAG
;
S DNSFLAG=0 ;DNS has not been contacted for IP
;
S:'$G(HLCSTATE("SERVER")) IP=HLCSTATE("LINK","IP")
S PORT=HLCSTATE("LINK","PORT")
S HLCSTATE("CONNECTED")=0
S HLCSTATE("READ HEADER")="READHDR^HLOTCP"
S HLCSTATE("WRITE HEADER")="WRITEHDR^HLOTCP"
S HLCSTATE("READ SEGMENT")="READSEG^HLOTCP"
S HLCSTATE("WRITE SEGMENT")="WRITESEG^HLOTCP"
S HLCSTATE("END MESSAGE")="ENDMSG^HLOTCP"
S HLCSTATE("CLOSE")="CLOSE^HLOTCP"
S HLCSTATE("TCP BUFFER")=""
S HLCSTATE("TCP BUFFER $X")=0
;
;spawned by TaskMan multi-listener? If so, the device has already been opened
I $G(HLCSTATE("SERVER")),$G(HLCSTATE("LINK","SERVER"))="1^M",$G(LOGICAL)="" D Q
.S HLCSTATE("DEVICE")=IO(0),HLCSTATE("FLUSH")="!",HLCSTATE("TCP BUFFER SIZE")=512
.S HLCSTATE("CONNECTED")=1
;
;if no IP, not a server, give DNS a shot
I '$G(HLCSTATE("SERVER")),IP="" S DNSFLAG=1,IP=$$DNS(HLCSTATE("LINK","DOMAIN")),HLCSTATE("LINK","IP")=IP Q:IP=""
;
RETRY ;
;
I HLCSTATE("SYSTEM","OS")="DSM" D
.S HLCSTATE("TCP BUFFER SIZE")=512
.I $G(LOGICAL)]"" S HLCSTATE("DEVICE")=LOGICAL
.E S HLCSTATE("DEVICE")=PORT
.S HLCSTATE("FLUSH")="!"
.I $G(HLCSTATE("SERVER")) D
..O:$G(LOGICAL)]"" HLCSTATE("DEVICE"):(TCPDEV,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
..O:$G(LOGICAL)="" HLCSTATE("DEVICE"):(TCPCHAN,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
..I $T D
...S HLCSTATE("CONNECTED")=1
...U HLCSTATE("DEVICE"):NOECHO
.E D ;client
..O HLCSTATE("DEVICE"):(TCPCHAN,ADDRESS=IP,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
..I $T D
...S HLCSTATE("CONNECTED")=1
...U HLCSTATE("DEVICE"):NOECHO
E I HLCSTATE("SYSTEM","OS")="CACHE" D
.S HLCSTATE("FLUSH")="!"
.I $G(LOGICAL)]"" S HLCSTATE("DEVICE")=LOGICAL
.E S HLCSTATE("DEVICE")="|TCP|"_PORT
.S HLCSTATE("TCP BUFFER SIZE")=512
.I $G(HLCSTATE("SERVER")) D
..I HLCSTATE("SERVER")="1^S" D Q
...;single server (no concurrent connections)
ZB25 ...;
...O HLCSTATE("DEVICE"):(:PORT:"+A-S":::):HLCSTATE("OPEN TIMEOUT")
...I $T D
....N A
ZB26 ....S HLCSTATE("CONNECTED")=1
....U HLCSTATE("DEVICE")
....F R *A:HLCSTATE("READ TIMEOUT") Q:$T I $$CHKSTOP^HLOPROC S HLCSTATE("CONNECTED")=0 D CLOSE(.HLCSTATE) Q
ZB27 ....;
...E D
ZB28 ....;
..;multi-server spawned by OS - VMS TCP Services
..O HLCSTATE("DEVICE")::HLCSTATE("OPEN TIMEOUT") I '$T S HLCSTATE("CONNECTED")=0 Q
..S HLCSTATE("CONNECTED")=1
..U HLCSTATE("DEVICE"):(::"-S")
..;
.E D ;client
..S HLCSTATE("TCP BUFFER SIZE")=512
..O HLCSTATE("DEVICE"):(IP:PORT:"-S":::):HLCSTATE("OPEN TIMEOUT")
..I $T D
...S HLCSTATE("CONNECTED")=1
E D ;any other system but Cache or DSM
.S HLCSTATE("TCP BUFFER SIZE")=256
.D CALL^%ZISTCP(IP,PORT,HLCSTATE("OPEN TIMEOUT"))
.S HLCSTATE("CONNECTED")='POP
.I HLCSTATE("CONNECTED") S HLCSTATE("DEVICE")=IO
;
;if not connected, not the server, give DNS a shot if not tried already
I '$G(HLCSTATE("SERVER")),'HLCSTATE("CONNECTED"),'DNSFLAG S DNSFLAG=1,IP=$$DNS(HLCSTATE("LINK","DOMAIN")) I IP]"",IP'=HLCSTATE("LINK","IP") S HLCSTATE("LINK","IP")=IP Q:IP="" G RETRY
;
I HLCSTATE("CONNECTED"),DNSFLAG S $P(^HLCS(870,HLCSTATE("LINK","IEN"),400),"^")=IP
Q
;
DNS(DOMAIN) ;
Q $P($$ADDRESS^XLFNSLK(DOMAIN),",")
;
WRITEHDR(HLCSTATE,HDR) ;
;
;insure that package buffer is empty
K HLCSTATE("BUFFER")
S HLCSTATE("BUFFER","BYTE COUNT")=0
S HLCSTATE("BUFFER","SEGMENT COUNT")=0
;
;Start the message with <SB>, then write the header
N SEG
S SEG(1)=$C(11)_HDR(1)
S SEG(2)=HDR(2)
Q $$WRITESEG(.HLCSTATE,.SEG)
;
WRITESEG(HLCSTATE,SEG) ;
N I,LAST
S HLCSTATE("BUFFER","SEGMENT COUNT")=HLCSTATE("BUFFER","SEGMENT COUNT")+1
S I=0,LAST=$O(SEG(99999),-1)
F S I=$O(SEG(I)) Q:'I D
.I HLCSTATE("BUFFER","BYTE COUNT")>HLCSTATE("SYSTEM","BUFFER") D FLUSH
.I I=LAST S SEG(I)=SEG(I)_$C(13)
.S HLCSTATE("BUFFER",HLCSTATE("BUFFER","SEGMENT COUNT"),I)=SEG(I),HLCSTATE("BUFFER","BYTE COUNT")=HLCSTATE("BUFFER","BYTE COUNT")+$L(SEG(I))+20
Q HLCSTATE("CONNECTED")
;
FLUSH ;flushes the HL7 package buffer, and the system TCP buffer when full
N SEGMENT,MAX
S SEGMENT=0
;
S MAX=HLCSTATE("TCP BUFFER SIZE")-2
;
U HLCSTATE("DEVICE") I (HLCSTATE("SYSTEM","OS")="CACHE") S HLCSTATE("CONNECTED")=($ZA\8192#2) I 'HLCSTATE("CONNECTED") D CLOSE(.HLCSTATE)
F S SEGMENT=$O(HLCSTATE("BUFFER",SEGMENT)) Q:'SEGMENT D
.N I S I=0
.F S I=$O(HLCSTATE("BUFFER",SEGMENT,I)) Q:'I D
..N LINE
..S LINE=HLCSTATE("BUFFER",SEGMENT,I)
..;put the line in the TCP buffer, or as much as will fit - flush the buffer when it gets full
..F Q:LINE="" D
...N INC
...;INC is how much space is left in the buffer
...S INC=MAX-HLCSTATE("TCP BUFFER $X")
...I '($L(LINE)>INC) D
....S HLCSTATE("TCP BUFFER")=HLCSTATE("TCP BUFFER")_LINE
....S HLCSTATE("TCP BUFFER $X")=HLCSTATE("TCP BUFFER $X")+$L(LINE)
....S LINE=""
...E D
....S HLCSTATE("TCP BUFFER")=HLCSTATE("TCP BUFFER")_$E(LINE,1,INC)
....S HLCSTATE("TCP BUFFER $X")=MAX
....S LINE=$E(LINE,INC+1,99999)
...I HLCSTATE("TCP BUFFER $X")=MAX D
....W HLCSTATE("TCP BUFFER"),@HLCSTATE("FLUSH")
....S HLCSTATE("TCP BUFFER")="",HLCSTATE("TCP BUFFER $X")=0
K HLCSTATE("BUFFER")
S HLCSTATE("BUFFER","SEGMENT COUNT")=1
S HLCSTATE("BUFFER","BYTE COUNT")=0
Q
;
READSEG(HLCSTATE,SEG) ;
;
;Output:
; SEG - returns the segment (pass by reference)
; Function returns 1 on success, 0 on failure
;
K SEG
;**START P139 CJM - if the header segment has been read, and <EB> is encountered before the <CR>, then accept whatever came before <EB> as a segment
Q:HLCSTATE("MESSAGE ENDED") 0
;**END P139
;
N SUCCESS,COUNT,BUF
S (COUNT,SUCCESS)=0
;
;anything left from last read?
S BUF=HLCSTATE("READ")
S HLCSTATE("READ")=""
I BUF]"" D ;something was left!
.S COUNT=1
.I BUF[$C(13) D Q
..S SEG(1)=$P(BUF,$C(13)),BUF=$P(BUF,$C(13),2,999999)
..S SUCCESS=1
.;**START P139 CJM
.I HLCSTATE("MESSAGE STARTED"),BUF[$C(28) D Q
..S SEG(1)=$P(BUF,$C(28)),BUF=$P(BUF,$C(28),2,999999)
..S SUCCESS=1
..S HLCSTATE("MESSAGE ENDED")=1
.;**END P139 CJM
.S SEG(1)=BUF,BUF=""
;
; *** Begin HL*1.6*146 - RBN ***
;I 'SUCCESS U HLCSTATE("DEVICE") F R BUF:HLCSTATE("READ TIMEOUT") Q:'$T D Q:SUCCESS
I 'SUCCESS U HLCSTATE("DEVICE") F Q:'$$READ(.BUF) D Q:SUCCESS
.;** End HL*1.6*146 - RBN ***
.;
.I BUF[$C(13) S SUCCESS=1,COUNT=COUNT+1,SEG(COUNT)=$P(BUF,$C(13)),BUF=$P(BUF,$C(13),2,999999) Q
.;
.;**START P139 CJM
.I HLCSTATE("MESSAGE STARTED"),BUF[$C(28) S SUCCESS=1,HLCSTATE("MESSAGE ENDED")=1,COUNT=COUNT+1,SEG(COUNT)=$P(BUF,$C(28)),BUF=$P(BUF,$C(28),2,999999) Q
.;**END P139 CJM
.;
.S COUNT=COUNT+1,SEG(COUNT)=BUF
;
I SUCCESS D
.S HLCSTATE("READ")=BUF ;save the leftover
.I COUNT>1,SEG(COUNT)="" K SEG(COUNT) S COUNT=COUNT-1
;Cache can return the connection status
E I (HLCSTATE("SYSTEM","OS")="CACHE") S HLCSTATE("CONNECTED")=($ZA\8192#2) I 'HLCSTATE("CONNECTED") D CLOSE(.HLCSTATE)
;
;if the <EB> character was encountered, then there are no more segments in the message, set the end of message flag
I SUCCESS,SEG(COUNT)[$C(28) D
.K SEG
.S SUCCESS=0
.S HLCSTATE("MESSAGE ENDED")=1
Q SUCCESS
;
READHDR(HLCSTATE,HDR) ;
;reads the next header segment in the message stream, discarding everything that comes before it
;
N SEG,SUCCESS,J,I
S SUCCESS=0
K HDR
F Q:'$$READSEG(.HLCSTATE,.SEG) D Q:SUCCESS
.S I=0
.;look for the <SB>
.;perhaps the <SB> isn't in the first line
.F S I=$O(SEG(I)) Q:'I D Q:SUCCESS
..I (SEG(I)'[$C(11)) K SEG(I) Q
..S SEG(I)=$P(SEG(I),$C(11),2)
..S SUCCESS=1
..K:SEG(I)="" SEG(I)
I SUCCESS S (I,J)=0 F S J=$O(SEG(J)) Q:'J S I=I+1,HDR(I)=SEG(J)
Q SUCCESS
;
CLOSE(HLCSTATE) ;
CLOSE HLCSTATE("DEVICE")
;**P146 START CJM
I $G(HLCSTATE("READ TIMEOUT","CHANGED")) D PUTTIME(.HLCSTATE)
;**P146 END CJM
Q
;
ENDMSG(HLCSTATE) ;
N SEG
S SEG(1)=$C(28)
I $$WRITESEG(.HLCSTATE,.SEG) D Q 1
.D FLUSH
.I HLCSTATE("TCP BUFFER $X") D
..U HLCSTATE("DEVICE")
..W HLCSTATE("TCP BUFFER"),@HLCSTATE("FLUSH")
..S HLCSTATE("TCP BUFFER")=""
..S HLCSTATE("TCP BUFFER $X")=0
Q 0
;
;**P146 START CJM
READ(BUF) ;
;Performs a READ to BUF and returns the $T result as the function value.
;For client reads the timeout value is dynamically adjusted based
;on a random sample. For server reads the timeout is static.
;
;
ZB31 ;
N RETURN
S RETURN=0
;for the server the timeout is static
I $G(HLCSTATE("SERVER")) D
.R BUF:HLCSTATE("READ TIMEOUT")
.S RETURN=$T
;
E D ;client
.I ($R(100)<10) D
..;measure how long the READ really takes
.. N T1,T2
.. S T1=$$NOW^XLFDT
.. R BUF:100
..I $T D
...S RETURN=1
...S T2=$$NOW^XLFDT
...D SETTIME($$FMDIFF^XLFDT(T2,T1,2))
..E D
...S RETURN=0
.E D
..R BUF:HLCSTATE("READ TIMEOUT")
..S RETURN=$T
ZB32 ;
;
Q RETURN
;
SETTIME(TIME) ;
;Re-sets the Read Timeout based on an algorithm that uses the
;new read time + the prior 4 historical values.
;
N MAX,I,TEMP
S HLCSTATE("READ TIMEOUT","HISTORICAL")=TIME_"^"_$P(HLCSTATE("READ TIMEOUT","HISTORICAL"),"^",1,4)
S MAX=0
F I=1:1:5 S TEMP=$P(HLCSTATE("READ TIMEOUT","HISTORICAL"),"^",I) I TEMP>MAX S MAX=TEMP
S TEMP=MAX+5
I TEMP<20 S TEMP=20
I TEMP>60 S TEMP=60
S HLCSTATE("READ TIMEOUT")=TEMP
S HLCSTATE("READ TIMEOUT","CHANGED")=1
Q
;
GETTIME(HLCSTATE) ;
;Gets from ^HLTMP the current read timeout for the client link and the
;historical data that the timeout value is based on.
N DATA
S DATA=$G(^HLTMP("READ TIMEOUT",HLCSTATE("LINK","NAME")))
I $P(DATA,"^")<20 D
.S HLCSTATE("READ TIMEOUT")=20
E D
.S HLCSTATE("READ TIMEOUT")=$P(DATA,"^")
S HLCSTATE("READ TIMEOUT","HISTORICAL")=$P(DATA,"^",2,6)
S HLCSTATE("READ TIMEOUT","CHANGED")=0
Q
;
PUTTIME(HLCSTATE) ;
;Stores to ^HLTMP the current read timeout for the client link and
;the historical data that the timeout value is based on.
S ^HLTMP("READ TIMEOUT",HLCSTATE("LINK","NAME"))=HLCSTATE("READ TIMEOUT")_"^"_HLCSTATE("READ TIMEOUT","HISTORICAL")
Q
;**P146 END CJM
--- Routine Detail --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HHLOTCP 10975 printed Oct 16, 2024@18:00:02 Page 2
HLOTCP ;ALB/CJM- TCP/IP I/O - 10/4/94 1pm ;03/01/2011
+1 ;;1.6;HEALTH LEVEL SEVEN;**126,131,134,137,138,139,146,153**;Oct 13, 1995;Build 11
+2 ;Per VHA Directive 2004-038, this routine should not be modified.
+3 ;
OPEN(HLCSTATE,LOGICAL) ;
+1 ;This may be called either in the context of a client or a server.
+2 ;For the server, there are 3 situations:
+3 ; 1) The server is not concurrent. In this case the TCP device should be opened.
+4 ; 2) The server is concurrent, but this process was spawned by the OS
+5 ; (via a VMS TCP Service) In this case, the device should be opened
+6 ; via the LOGICAL that was passed in.
+7 ; 3) The server is concurrent, but this process was spawned by the
+8 ; TaskMan multi-listener. In this case TaskMan already opened the
+9 ; device. This case can be determined by the absence of the LOGICAL
+10 ; input parameter.
+11 ;
+12 NEW IP,PORT,DNSFLAG
+13 ;
+14 ;DNS has not been contacted for IP
SET DNSFLAG=0
+15 ;
+16 if '$GET(HLCSTATE("SERVER"))
SET IP=HLCSTATE("LINK","IP")
+17 SET PORT=HLCSTATE("LINK","PORT")
+18 SET HLCSTATE("CONNECTED")=0
+19 SET HLCSTATE("READ HEADER")="READHDR^HLOTCP"
+20 SET HLCSTATE("WRITE HEADER")="WRITEHDR^HLOTCP"
+21 SET HLCSTATE("READ SEGMENT")="READSEG^HLOTCP"
+22 SET HLCSTATE("WRITE SEGMENT")="WRITESEG^HLOTCP"
+23 SET HLCSTATE("END MESSAGE")="ENDMSG^HLOTCP"
+24 SET HLCSTATE("CLOSE")="CLOSE^HLOTCP"
+25 SET HLCSTATE("TCP BUFFER")=""
+26 SET HLCSTATE("TCP BUFFER $X")=0
+27 ;
+28 ;spawned by TaskMan multi-listener? If so, the device has already been opened
+29 IF $GET(HLCSTATE("SERVER"))
IF $GET(HLCSTATE("LINK","SERVER"))="1^M"
IF $GET(LOGICAL)=""
Begin DoDot:1
+30 SET HLCSTATE("DEVICE")=IO(0)
SET HLCSTATE("FLUSH")="!"
SET HLCSTATE("TCP BUFFER SIZE")=512
+31 SET HLCSTATE("CONNECTED")=1
End DoDot:1
QUIT
+32 ;
+33 ;if no IP, not a server, give DNS a shot
+34 IF '$GET(HLCSTATE("SERVER"))
IF IP=""
SET DNSFLAG=1
SET IP=$$DNS(HLCSTATE("LINK","DOMAIN"))
SET HLCSTATE("LINK","IP")=IP
if IP=""
QUIT
+35 ;
RETRY ;
+1 ;
+2 IF HLCSTATE("SYSTEM","OS")="DSM"
Begin DoDot:1
+3 SET HLCSTATE("TCP BUFFER SIZE")=512
+4 IF $GET(LOGICAL)]""
SET HLCSTATE("DEVICE")=LOGICAL
+5 IF '$TEST
SET HLCSTATE("DEVICE")=PORT
+6 SET HLCSTATE("FLUSH")="!"
+7 IF $GET(HLCSTATE("SERVER"))
Begin DoDot:2
+8 if $GET(LOGICAL)]""
OPEN HLCSTATE("DEVICE"):(TCPDEV,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
+9 if $GET(LOGICAL)=""
OPEN HLCSTATE("DEVICE"):(TCPCHAN,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
+10 IF $TEST
Begin DoDot:3
+11 SET HLCSTATE("CONNECTED")=1
+12 USE HLCSTATE("DEVICE"):NOECHO
End DoDot:3
End DoDot:2
+13 ;client
IF '$TEST
Begin DoDot:2
+14 OPEN HLCSTATE("DEVICE"):(TCPCHAN,ADDRESS=IP,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT")
+15 IF $TEST
Begin DoDot:3
+16 SET HLCSTATE("CONNECTED")=1
+17 USE HLCSTATE("DEVICE"):NOECHO
End DoDot:3
End DoDot:2
End DoDot:1
+18 IF '$TEST
IF HLCSTATE("SYSTEM","OS")="CACHE"
Begin DoDot:1
+19 SET HLCSTATE("FLUSH")="!"
+20 IF $GET(LOGICAL)]""
SET HLCSTATE("DEVICE")=LOGICAL
+21 IF '$TEST
SET HLCSTATE("DEVICE")="|TCP|"_PORT
+22 SET HLCSTATE("TCP BUFFER SIZE")=512
+23 IF $GET(HLCSTATE("SERVER"))
Begin DoDot:2
+24 IF HLCSTATE("SERVER")="1^S"
Begin DoDot:3
+25 ;single server (no concurrent connections)
ZB25 ;
+1 OPEN HLCSTATE("DEVICE"):(:PORT:"+A-S":::):HLCSTATE("OPEN TIMEOUT")
+2 IF $TEST
Begin DoDot:4
+3 NEW A
ZB26 SET HLCSTATE("CONNECTED")=1
+1 USE HLCSTATE("DEVICE")
+2 FOR
READ *A:HLCSTATE("READ TIMEOUT")
if $TEST
QUIT
IF $$CHKSTOP^HLOPROC
SET HLCSTATE("CONNECTED")=0
DO CLOSE(.HLCSTATE)
QUIT
ZB27 ;
End DoDot:4
+1 IF '$TEST
Begin DoDot:4
ZB28 ;
End DoDot:4
End DoDot:3
QUIT
+1 ;multi-server spawned by OS - VMS TCP Services
+2 OPEN HLCSTATE("DEVICE")::HLCSTATE("OPEN TIMEOUT")
IF '$TEST
SET HLCSTATE("CONNECTED")=0
QUIT
+3 SET HLCSTATE("CONNECTED")=1
+4 USE HLCSTATE("DEVICE"):(::"-S")
+5 ;
End DoDot:2
+6 ;client
IF '$TEST
Begin DoDot:2
+7 SET HLCSTATE("TCP BUFFER SIZE")=512
+8 OPEN HLCSTATE("DEVICE"):(IP:PORT:"-S":::):HLCSTATE("OPEN TIMEOUT")
+9 IF $TEST
Begin DoDot:3
+10 SET HLCSTATE("CONNECTED")=1
End DoDot:3
End DoDot:2
End DoDot:1
+11 ;any other system but Cache or DSM
IF '$TEST
Begin DoDot:1
+12 SET HLCSTATE("TCP BUFFER SIZE")=256
+13 DO CALL^%ZISTCP(IP,PORT,HLCSTATE("OPEN TIMEOUT"))
+14 SET HLCSTATE("CONNECTED")='POP
+15 IF HLCSTATE("CONNECTED")
SET HLCSTATE("DEVICE")=IO
End DoDot:1
+16 ;
+17 ;if not connected, not the server, give DNS a shot if not tried already
+18 IF '$GET(HLCSTATE("SERVER"))
IF 'HLCSTATE("CONNECTED")
IF 'DNSFLAG
SET DNSFLAG=1
SET IP=$$DNS(HLCSTATE("LINK","DOMAIN"))
IF IP]""
IF IP'=HLCSTATE("LINK","IP")
SET HLCSTATE("LINK","IP")=IP
if IP=""
QUIT
GOTO RETRY
+19 ;
+20 IF HLCSTATE("CONNECTED")
IF DNSFLAG
SET $PIECE(^HLCS(870,HLCSTATE("LINK","IEN"),400),"^")=IP
+21 QUIT
+22 ;
DNS(DOMAIN) ;
+1 QUIT $PIECE($$ADDRESS^XLFNSLK(DOMAIN),",")
+2 ;
WRITEHDR(HLCSTATE,HDR) ;
+1 ;
+2 ;insure that package buffer is empty
+3 KILL HLCSTATE("BUFFER")
+4 SET HLCSTATE("BUFFER","BYTE COUNT")=0
+5 SET HLCSTATE("BUFFER","SEGMENT COUNT")=0
+6 ;
+7 ;Start the message with <SB>, then write the header
+8 NEW SEG
+9 SET SEG(1)=$CHAR(11)_HDR(1)
+10 SET SEG(2)=HDR(2)
+11 QUIT $$WRITESEG(.HLCSTATE,.SEG)
+12 ;
WRITESEG(HLCSTATE,SEG) ;
+1 NEW I,LAST
+2 SET HLCSTATE("BUFFER","SEGMENT COUNT")=HLCSTATE("BUFFER","SEGMENT COUNT")+1
+3 SET I=0
SET LAST=$ORDER(SEG(99999),-1)
+4 FOR
SET I=$ORDER(SEG(I))
if 'I
QUIT
Begin DoDot:1
+5 IF HLCSTATE("BUFFER","BYTE COUNT")>HLCSTATE("SYSTEM","BUFFER")
DO FLUSH
+6 IF I=LAST
SET SEG(I)=SEG(I)_$CHAR(13)
+7 SET HLCSTATE("BUFFER",HLCSTATE("BUFFER","SEGMENT COUNT"),I)=SEG(I)
SET HLCSTATE("BUFFER","BYTE COUNT")=HLCSTATE("BUFFER","BYTE COUNT")+$LENGTH(SEG(I))+20
End DoDot:1
+8 QUIT HLCSTATE("CONNECTED")
+9 ;
FLUSH ;flushes the HL7 package buffer, and the system TCP buffer when full
+1 NEW SEGMENT,MAX
+2 SET SEGMENT=0
+3 ;
+4 SET MAX=HLCSTATE("TCP BUFFER SIZE")-2
+5 ;
+6 USE HLCSTATE("DEVICE")
IF (HLCSTATE("SYSTEM","OS")="CACHE")
SET HLCSTATE("CONNECTED")=($ZA\8192#2)
IF 'HLCSTATE("CONNECTED")
DO CLOSE(.HLCSTATE)
+7 FOR
SET SEGMENT=$ORDER(HLCSTATE("BUFFER",SEGMENT))
if 'SEGMENT
QUIT
Begin DoDot:1
+8 NEW I
SET I=0
+9 FOR
SET I=$ORDER(HLCSTATE("BUFFER",SEGMENT,I))
if 'I
QUIT
Begin DoDot:2
+10 NEW LINE
+11 SET LINE=HLCSTATE("BUFFER",SEGMENT,I)
+12 ;put the line in the TCP buffer, or as much as will fit - flush the buffer when it gets full
+13 FOR
if LINE=""
QUIT
Begin DoDot:3
+14 NEW INC
+15 ;INC is how much space is left in the buffer
+16 SET INC=MAX-HLCSTATE("TCP BUFFER $X")
+17 IF '($LENGTH(LINE)>INC)
Begin DoDot:4
+18 SET HLCSTATE("TCP BUFFER")=HLCSTATE("TCP BUFFER")_LINE
+19 SET HLCSTATE("TCP BUFFER $X")=HLCSTATE("TCP BUFFER $X")+$LENGTH(LINE)
+20 SET LINE=""
End DoDot:4
+21 IF '$TEST
Begin DoDot:4
+22 SET HLCSTATE("TCP BUFFER")=HLCSTATE("TCP BUFFER")_$EXTRACT(LINE,1,INC)
+23 SET HLCSTATE("TCP BUFFER $X")=MAX
+24 SET LINE=$EXTRACT(LINE,INC+1,99999)
End DoDot:4
+25 IF HLCSTATE("TCP BUFFER $X")=MAX
Begin DoDot:4
+26 WRITE HLCSTATE("TCP BUFFER"),@HLCSTATE("FLUSH")
+27 SET HLCSTATE("TCP BUFFER")=""
SET HLCSTATE("TCP BUFFER $X")=0
End DoDot:4
End DoDot:3
End DoDot:2
End DoDot:1
+28 KILL HLCSTATE("BUFFER")
+29 SET HLCSTATE("BUFFER","SEGMENT COUNT")=1
+30 SET HLCSTATE("BUFFER","BYTE COUNT")=0
+31 QUIT
+32 ;
READSEG(HLCSTATE,SEG) ;
+1 ;
+2 ;Output:
+3 ; SEG - returns the segment (pass by reference)
+4 ; Function returns 1 on success, 0 on failure
+5 ;
+6 KILL SEG
+7 ;**START P139 CJM - if the header segment has been read, and <EB> is encountered before the <CR>, then accept whatever came before <EB> as a segment
+8 if HLCSTATE("MESSAGE ENDED")
QUIT 0
+9 ;**END P139
+10 ;
+11 NEW SUCCESS,COUNT,BUF
+12 SET (COUNT,SUCCESS)=0
+13 ;
+14 ;anything left from last read?
+15 SET BUF=HLCSTATE("READ")
+16 SET HLCSTATE("READ")=""
+17 ;something was left!
IF BUF]""
Begin DoDot:1
+18 SET COUNT=1
+19 IF BUF[$CHAR(13)
Begin DoDot:2
+20 SET SEG(1)=$PIECE(BUF,$CHAR(13))
SET BUF=$PIECE(BUF,$CHAR(13),2,999999)
+21 SET SUCCESS=1
End DoDot:2
QUIT
+22 ;**START P139 CJM
+23 IF HLCSTATE("MESSAGE STARTED")
IF BUF[$CHAR(28)
Begin DoDot:2
+24 SET SEG(1)=$PIECE(BUF,$CHAR(28))
SET BUF=$PIECE(BUF,$CHAR(28),2,999999)
+25 SET SUCCESS=1
+26 SET HLCSTATE("MESSAGE ENDED")=1
End DoDot:2
QUIT
+27 ;**END P139 CJM
+28 SET SEG(1)=BUF
SET BUF=""
End DoDot:1
+29 ;
+30 ; *** Begin HL*1.6*146 - RBN ***
+31 ;I 'SUCCESS U HLCSTATE("DEVICE") F R BUF:HLCSTATE("READ TIMEOUT") Q:'$T D Q:SUCCESS
+32 IF 'SUCCESS
USE HLCSTATE("DEVICE")
FOR
if '$$READ(.BUF)
QUIT
Begin DoDot:1
+33 ;** End HL*1.6*146 - RBN ***
+34 ;
+35 IF BUF[$CHAR(13)
SET SUCCESS=1
SET COUNT=COUNT+1
SET SEG(COUNT)=$PIECE(BUF,$CHAR(13))
SET BUF=$PIECE(BUF,$CHAR(13),2,999999)
QUIT
+36 ;
+37 ;**START P139 CJM
+38 IF HLCSTATE("MESSAGE STARTED")
IF BUF[$CHAR(28)
SET SUCCESS=1
SET HLCSTATE("MESSAGE ENDED")=1
SET COUNT=COUNT+1
SET SEG(COUNT)=$PIECE(BUF,$CHAR(28))
SET BUF=$PIECE(BUF,$CHAR(28),2,999999)
QUIT
+39 ;**END P139 CJM
+40 ;
+41 SET COUNT=COUNT+1
SET SEG(COUNT)=BUF
End DoDot:1
if SUCCESS
QUIT
+42 ;
+43 IF SUCCESS
Begin DoDot:1
+44 ;save the leftover
SET HLCSTATE("READ")=BUF
+45 IF COUNT>1
IF SEG(COUNT)=""
KILL SEG(COUNT)
SET COUNT=COUNT-1
End DoDot:1
+46 ;Cache can return the connection status
+47 IF '$TEST
IF (HLCSTATE("SYSTEM","OS")="CACHE")
SET HLCSTATE("CONNECTED")=($ZA\8192#2)
IF 'HLCSTATE("CONNECTED")
DO CLOSE(.HLCSTATE)
+48 ;
+49 ;if the <EB> character was encountered, then there are no more segments in the message, set the end of message flag
+50 IF SUCCESS
IF SEG(COUNT)[$CHAR(28)
Begin DoDot:1
+51 KILL SEG
+52 SET SUCCESS=0
+53 SET HLCSTATE("MESSAGE ENDED")=1
End DoDot:1
+54 QUIT SUCCESS
+55 ;
READHDR(HLCSTATE,HDR) ;
+1 ;reads the next header segment in the message stream, discarding everything that comes before it
+2 ;
+3 NEW SEG,SUCCESS,J,I
+4 SET SUCCESS=0
+5 KILL HDR
+6 FOR
if '$$READSEG(.HLCSTATE,.SEG)
QUIT
Begin DoDot:1
+7 SET I=0
+8 ;look for the <SB>
+9 ;perhaps the <SB> isn't in the first line
+10 FOR
SET I=$ORDER(SEG(I))
if 'I
QUIT
Begin DoDot:2
+11 IF (SEG(I)'[$CHAR(11))
KILL SEG(I)
QUIT
+12 SET SEG(I)=$PIECE(SEG(I),$CHAR(11),2)
+13 SET SUCCESS=1
+14 if SEG(I)=""
KILL SEG(I)
End DoDot:2
if SUCCESS
QUIT
End DoDot:1
if SUCCESS
QUIT
+15 IF SUCCESS
SET (I,J)=0
FOR
SET J=$ORDER(SEG(J))
if 'J
QUIT
SET I=I+1
SET HDR(I)=SEG(J)
+16 QUIT SUCCESS
+17 ;
CLOSE(HLCSTATE) ;
+1 CLOSE HLCSTATE("DEVICE")
+2 ;**P146 START CJM
+3 IF $GET(HLCSTATE("READ TIMEOUT","CHANGED"))
DO PUTTIME(.HLCSTATE)
+4 ;**P146 END CJM
+5 QUIT
+6 ;
ENDMSG(HLCSTATE) ;
+1 NEW SEG
+2 SET SEG(1)=$CHAR(28)
+3 IF $$WRITESEG(.HLCSTATE,.SEG)
Begin DoDot:1
+4 DO FLUSH
+5 IF HLCSTATE("TCP BUFFER $X")
Begin DoDot:2
+6 USE HLCSTATE("DEVICE")
+7 WRITE HLCSTATE("TCP BUFFER"),@HLCSTATE("FLUSH")
+8 SET HLCSTATE("TCP BUFFER")=""
+9 SET HLCSTATE("TCP BUFFER $X")=0
End DoDot:2
End DoDot:1
QUIT 1
+10 QUIT 0
+11 ;
+12 ;**P146 START CJM
READ(BUF) ;
+1 ;Performs a READ to BUF and returns the $T result as the function value.
+2 ;For client reads the timeout value is dynamically adjusted based
+3 ;on a random sample. For server reads the timeout is static.
+4 ;
+5 ;
ZB31 ;
+1 NEW RETURN
+2 SET RETURN=0
+3 ;for the server the timeout is static
+4 IF $GET(HLCSTATE("SERVER"))
Begin DoDot:1
+5 READ BUF:HLCSTATE("READ TIMEOUT")
+6 SET RETURN=$TEST
End DoDot:1
+7 ;
+8 ;client
IF '$TEST
Begin DoDot:1
+9 IF ($RANDOM(100)<10)
Begin DoDot:2
+10 ;measure how long the READ really takes
+11 NEW T1,T2
+12 SET T1=$$NOW^XLFDT
+13 READ BUF:100
+14 IF $TEST
Begin DoDot:3
+15 SET RETURN=1
+16 SET T2=$$NOW^XLFDT
+17 DO SETTIME($$FMDIFF^XLFDT(T2,T1,2))
End DoDot:3
+18 IF '$TEST
Begin DoDot:3
+19 SET RETURN=0
End DoDot:3
End DoDot:2
+20 IF '$TEST
Begin DoDot:2
+21 READ BUF:HLCSTATE("READ TIMEOUT")
+22 SET RETURN=$TEST
End DoDot:2
End DoDot:1
ZB32 ;
+1 ;
+2 QUIT RETURN
+3 ;
SETTIME(TIME) ;
+1 ;Re-sets the Read Timeout based on an algorithm that uses the
+2 ;new read time + the prior 4 historical values.
+3 ;
+4 NEW MAX,I,TEMP
+5 SET HLCSTATE("READ TIMEOUT","HISTORICAL")=TIME_"^"_$PIECE(HLCSTATE("READ TIMEOUT","HISTORICAL"),"^",1,4)
+6 SET MAX=0
+7 FOR I=1:1:5
SET TEMP=$PIECE(HLCSTATE("READ TIMEOUT","HISTORICAL"),"^",I)
IF TEMP>MAX
SET MAX=TEMP
+8 SET TEMP=MAX+5
+9 IF TEMP<20
SET TEMP=20
+10 IF TEMP>60
SET TEMP=60
+11 SET HLCSTATE("READ TIMEOUT")=TEMP
+12 SET HLCSTATE("READ TIMEOUT","CHANGED")=1
+13 QUIT
+14 ;
GETTIME(HLCSTATE) ;
+1 ;Gets from ^HLTMP the current read timeout for the client link and the
+2 ;historical data that the timeout value is based on.
+3 NEW DATA
+4 SET DATA=$GET(^HLTMP("READ TIMEOUT",HLCSTATE("LINK","NAME")))
+5 IF $PIECE(DATA,"^")<20
Begin DoDot:1
+6 SET HLCSTATE("READ TIMEOUT")=20
End DoDot:1
+7 IF '$TEST
Begin DoDot:1
+8 SET HLCSTATE("READ TIMEOUT")=$PIECE(DATA,"^")
End DoDot:1
+9 SET HLCSTATE("READ TIMEOUT","HISTORICAL")=$PIECE(DATA,"^",2,6)
+10 SET HLCSTATE("READ TIMEOUT","CHANGED")=0
+11 QUIT
+12 ;
PUTTIME(HLCSTATE) ;
+1 ;Stores to ^HLTMP the current read timeout for the client link and
+2 ;the historical data that the timeout value is based on.
+3 SET ^HLTMP("READ TIMEOUT",HLCSTATE("LINK","NAME"))=HLCSTATE("READ TIMEOUT")_"^"_HLCSTATE("READ TIMEOUT","HISTORICAL")
+4 QUIT
+5 ;**P146 END CJM