| 1 | HLOTCP ;ALB/CJM- TCP/IP I/O - 10/4/94 1pm ;07/10/2007 | 
|---|
| 2 | ;;1.6;HEALTH LEVEL SEVEN;**126,131,134,137**;Oct 13, 1995;Build 21 | 
|---|
| 3 | ;Per VHA Directive 2004-038, this routine should not be modified. | 
|---|
| 4 | ; | 
|---|
| 5 | OPEN(HLCSTATE,LOGICAL) ; | 
|---|
| 6 | ;This may be called either in the context of a client or a server. | 
|---|
| 7 | ;For the server, there are 3 situations: | 
|---|
| 8 | ; 1) The server is not concurrent.  In this case the TCP device should be opened. | 
|---|
| 9 | ; 2) The server is concurrent, but this process was spawned by the OS | 
|---|
| 10 | ;    (via a VMS TCP Service)  In this case, the device should be opened | 
|---|
| 11 | ;    via the LOGICAL that was passed in. | 
|---|
| 12 | ;  3) The server is concurrent, but this process was spawned by the | 
|---|
| 13 | ;     TaskMan multi-listener.  In this case TaskMan already opened the | 
|---|
| 14 | ;     device.  This case can be determined by the absence of the LOGICAL | 
|---|
| 15 | ;     input parameter. | 
|---|
| 16 | ; | 
|---|
| 17 | N IP,PORT,DNSFLAG | 
|---|
| 18 | ; | 
|---|
| 19 | S DNSFLAG=0 ;DNS has not been contacted for IP | 
|---|
| 20 | ; | 
|---|
| 21 | S:'$G(HLCSTATE("SERVER")) IP=HLCSTATE("LINK","IP") | 
|---|
| 22 | S PORT=HLCSTATE("LINK","PORT") | 
|---|
| 23 | S HLCSTATE("CONNECTED")=0 | 
|---|
| 24 | S HLCSTATE("READ HEADER")="READHDR^HLOTCP" | 
|---|
| 25 | S HLCSTATE("WRITE HEADER")="WRITEHDR^HLOTCP" | 
|---|
| 26 | S HLCSTATE("READ SEGMENT")="READSEG^HLOTCP" | 
|---|
| 27 | S HLCSTATE("WRITE SEGMENT")="WRITESEG^HLOTCP" | 
|---|
| 28 | S HLCSTATE("END MESSAGE")="ENDMSG^HLOTCP" | 
|---|
| 29 | S HLCSTATE("CLOSE")="CLOSE^HLOTCP" | 
|---|
| 30 | ; | 
|---|
| 31 | ;spawned by TaskMan multi-listener? If so, the device has already been opened | 
|---|
| 32 | I $G(HLCSTATE("SERVER")),$G(HLCSTATE("LINK","SERVER"))="1^M",$G(LOGICAL)="" D  Q | 
|---|
| 33 | .S HLCSTATE("DEVICE")=IO(0),HLCSTATE("FLUSH")="!",HLCSTATE("TCP BUFFER SIZE")=510 | 
|---|
| 34 | .S HLCSTATE("CONNECTED")=1 | 
|---|
| 35 | ; | 
|---|
| 36 | ;if no IP, not a server, give DNS a shot | 
|---|
| 37 | I '$G(HLCSTATE("SERVER")),IP="" S DNSFLAG=1,IP=$$DNS(HLCSTATE("LINK","DOMAIN")),HLCSTATE("LINK","IP")=IP Q:IP="" | 
|---|
| 38 | ; | 
|---|
| 39 | RETRY I HLCSTATE("SYSTEM","OS")="DSM" D | 
|---|
| 40 | .S HLCSTATE("TCP BUFFER SIZE")=512 | 
|---|
| 41 | .I $G(LOGICAL)]"" S HLCSTATE("DEVICE")=LOGICAL | 
|---|
| 42 | .E  S HLCSTATE("DEVICE")=PORT | 
|---|
| 43 | .S HLCSTATE("FLUSH")="!" | 
|---|
| 44 | .I $G(HLCSTATE("SERVER")) D | 
|---|
| 45 | ..O:$G(LOGICAL)]"" HLCSTATE("DEVICE"):(TCPDEV,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT") | 
|---|
| 46 | ..O:$G(LOGICAL)="" HLCSTATE("DEVICE"):(TCPCHAN,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT") | 
|---|
| 47 | ..I $T D | 
|---|
| 48 | ...S HLCSTATE("CONNECTED")=1 | 
|---|
| 49 | ...U HLCSTATE("DEVICE"):NOECHO | 
|---|
| 50 | .E  D  ;client | 
|---|
| 51 | ..O HLCSTATE("DEVICE"):(TCPCHAN,ADDRESS=IP,BLOCKSIZE=512):HLCSTATE("OPEN TIMEOUT") | 
|---|
| 52 | ..I $T D | 
|---|
| 53 | ...S HLCSTATE("CONNECTED")=1 | 
|---|
| 54 | ...U HLCSTATE("DEVICE"):NOECHO | 
|---|
| 55 | E  I HLCSTATE("SYSTEM","OS")="CACHE" D | 
|---|
| 56 | .S HLCSTATE("FLUSH")="!" | 
|---|
| 57 | .I $G(LOGICAL)]"" S HLCSTATE("DEVICE")=LOGICAL | 
|---|
| 58 | .E  S HLCSTATE("DEVICE")="|TCP|"_PORT | 
|---|
| 59 | .S HLCSTATE("TCP BUFFER SIZE")=510 | 
|---|
| 60 | .I $G(HLCSTATE("SERVER")) D | 
|---|
| 61 | ..I HLCSTATE("SERVER")="1^S" D  Q | 
|---|
| 62 | ...;single server (no concurrent connections) | 
|---|
| 63 | ...O HLCSTATE("DEVICE"):(:PORT:"+A-S":::):HLCSTATE("OPEN TIMEOUT") | 
|---|
| 64 | ...I $T D | 
|---|
| 65 | ....N A | 
|---|
| 66 | ....S HLCSTATE("CONNECTED")=1 | 
|---|
| 67 | ....U HLCSTATE("DEVICE") | 
|---|
| 68 | ....F  R *A:HLCSTATE("READ TIMEOUT") Q:$T  I $$CHKSTOP^HLOPROC S HLCSTATE("CONNECTED")=0 D CLOSE(.HLCSTATE) Q | 
|---|
| 69 | ..; | 
|---|
| 70 | ..;multi-server spawned by OS - VMS TCP Services | 
|---|
| 71 | ..O HLCSTATE("DEVICE")::HLCSTATE("OPEN TIMEOUT") I '$T S HLCSTATE("CONNECTED")=0 Q | 
|---|
| 72 | ..S HLCSTATE("CONNECTED")=1 | 
|---|
| 73 | ..U HLCSTATE("DEVICE"):(::"-S") | 
|---|
| 74 | ..; | 
|---|
| 75 | .E  D  ;client | 
|---|
| 76 | ..S HLCSTATE("TCP BUFFER SIZE")=510 | 
|---|
| 77 | ..O HLCSTATE("DEVICE"):(IP:PORT:"-S":::):HLCSTATE("OPEN TIMEOUT") | 
|---|
| 78 | ..I $T D | 
|---|
| 79 | ...S HLCSTATE("CONNECTED")=1 | 
|---|
| 80 | E  D  ;any other system but Cache or DSM | 
|---|
| 81 | .S HLCSTATE("TCP BUFFER SIZE")=256 | 
|---|
| 82 | .D CALL^%ZISTCP(IP,PORT,HLCSTATE("OPEN TIMEOUT")) | 
|---|
| 83 | .S HLCSTATE("CONNECTED")='POP | 
|---|
| 84 | .I HLCSTATE("CONNECTED") S HLCSTATE("DEVICE")=IO | 
|---|
| 85 | ; | 
|---|
| 86 | ;if not connected, not the server, give DNS a shot if not tried already | 
|---|
| 87 | 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 G RETRY | 
|---|
| 88 | I HLCSTATE("CONNECTED"),DNSFLAG S $P(^HLCS(870,HLCSTATE("LINK","IEN"),400),"^")=IP | 
|---|
| 89 | Q | 
|---|
| 90 | ; | 
|---|
| 91 | DNS(DOMAIN) ; | 
|---|
| 92 | Q $P($$ADDRESS^XLFNSLK(DOMAIN),",") | 
|---|
| 93 | ; | 
|---|
| 94 | WRITEHDR(HLCSTATE,HDR) ; | 
|---|
| 95 | ; | 
|---|
| 96 | ;insure that package buffer is empty | 
|---|
| 97 | K HLCSTATE("BUFFER") | 
|---|
| 98 | S HLCSTATE("BUFFER","BYTE COUNT")=0 | 
|---|
| 99 | S HLCSTATE("BUFFER","SEGMENT COUNT")=0 | 
|---|
| 100 | S HLCSTATE("FIRST WRITE")=1 ;so that FLUSH knows $X should be 0 | 
|---|
| 101 | ; | 
|---|
| 102 | ;Start the message with <SB>, then write the header | 
|---|
| 103 | N SEG | 
|---|
| 104 | S SEG(1)=$C(11)_HDR(1) | 
|---|
| 105 | S SEG(2)=HDR(2) | 
|---|
| 106 | Q $$WRITESEG(.HLCSTATE,.SEG) | 
|---|
| 107 | ; | 
|---|
| 108 | WRITESEG(HLCSTATE,SEG) ; | 
|---|
| 109 | N I,LAST | 
|---|
| 110 | S HLCSTATE("BUFFER","SEGMENT COUNT")=HLCSTATE("BUFFER","SEGMENT COUNT")+1 | 
|---|
| 111 | S I=0,LAST=$O(SEG(99999),-1) | 
|---|
| 112 | F  S I=$O(SEG(I)) Q:'I  D | 
|---|
| 113 | .I HLCSTATE("BUFFER","BYTE COUNT")>HLCSTATE("SYSTEM","BUFFER") D FLUSH | 
|---|
| 114 | .I I=LAST S SEG(I)=SEG(I)_$C(13) | 
|---|
| 115 | .S HLCSTATE("BUFFER",HLCSTATE("BUFFER","SEGMENT COUNT"),I)=SEG(I),HLCSTATE("BUFFER","BYTE COUNT")=HLCSTATE("BUFFER","BYTE COUNT")+$L(SEG(I))+20 | 
|---|
| 116 | Q HLCSTATE("CONNECTED") | 
|---|
| 117 | ; | 
|---|
| 118 | FLUSH ;flushes the HL7 package buffer, and the system TCP buffer when full | 
|---|
| 119 | N SEGMENT,MAX | 
|---|
| 120 | S SEGMENT=0 | 
|---|
| 121 | S MAX=HLCSTATE("TCP BUFFER SIZE") | 
|---|
| 122 | U HLCSTATE("DEVICE") I (HLCSTATE("SYSTEM","OS")="CACHE") S HLCSTATE("CONNECTED")=($ZA\8192#2) I 'HLCSTATE("CONNECTED") D CLOSE(.HLCSTATE) | 
|---|
| 123 | F  S SEGMENT=$O(HLCSTATE("BUFFER",SEGMENT)) Q:'SEGMENT  D | 
|---|
| 124 | .N I S I=0 | 
|---|
| 125 | .F  S I=$O(HLCSTATE("BUFFER",SEGMENT,I)) Q:'I  D | 
|---|
| 126 | ..N LINE,J | 
|---|
| 127 | ..S J=$S(HLCSTATE("FIRST WRITE"):0,1:$X) | 
|---|
| 128 | ..S HLCSTATE("FIRST WRITE")=0 | 
|---|
| 129 | ..S LINE=HLCSTATE("BUFFER",SEGMENT,I) | 
|---|
| 130 | ..F  Q:'(J+$L(LINE)>MAX)  D | 
|---|
| 131 | ...W $E(LINE,1,MAX-J),@HLCSTATE("FLUSH") S HLCSTATE("FLUSHED")=1 | 
|---|
| 132 | ...S LINE=$E(LINE,(MAX-J)+1,99999) | 
|---|
| 133 | ...S J=0 | 
|---|
| 134 | ..I (LINE]"") W LINE S HLCSTATE("FLUSHED")=0 | 
|---|
| 135 | K HLCSTATE("BUFFER") | 
|---|
| 136 | S HLCSTATE("BUFFER","SEGMENT COUNT")=1 | 
|---|
| 137 | S HLCSTATE("BUFFER","BYTE COUNT")=0 | 
|---|
| 138 | S HLCSTATE("FIRST WRITE")=0 | 
|---|
| 139 | Q | 
|---|
| 140 | ; | 
|---|
| 141 | READSEG(HLCSTATE,SEG) ; | 
|---|
| 142 | ; | 
|---|
| 143 | ;Output: | 
|---|
| 144 | ;  SEG - returns the segment (pass by reference) | 
|---|
| 145 | ;  Function returns 1 on success, 0 on failure | 
|---|
| 146 | ; | 
|---|
| 147 | N SUCCESS,COUNT,BUF | 
|---|
| 148 | S (COUNT,SUCCESS)=0 | 
|---|
| 149 | K SEG | 
|---|
| 150 | ; | 
|---|
| 151 | ;anything left from last read? | 
|---|
| 152 | S BUF=HLCSTATE("READ") | 
|---|
| 153 | S HLCSTATE("READ")="" | 
|---|
| 154 | I BUF]"" D  ;something was left! | 
|---|
| 155 | .S COUNT=1 | 
|---|
| 156 | .I BUF[$C(13) D  Q | 
|---|
| 157 | ..S SEG(1)=$P(BUF,$C(13)),BUF=$P(BUF,$C(13),2,9999) | 
|---|
| 158 | ..S SUCCESS=1 | 
|---|
| 159 | .S SEG(1)=BUF,BUF="" | 
|---|
| 160 | I 'SUCCESS U HLCSTATE("DEVICE") F  R BUF:HLCSTATE("READ TIMEOUT") Q:'$T  D  Q:SUCCESS | 
|---|
| 161 | .I BUF[$C(13) S SUCCESS=1,COUNT=COUNT+1,SEG(COUNT)=$P(BUF,$C(13)),BUF=$P(BUF,$C(13),2,9999) Q | 
|---|
| 162 | .S COUNT=COUNT+1,SEG(COUNT)=BUF | 
|---|
| 163 | ; | 
|---|
| 164 | I SUCCESS D | 
|---|
| 165 | .S HLCSTATE("READ")=BUF ;save the leftover | 
|---|
| 166 | .I COUNT>1,SEG(COUNT)="" K SEG(COUNT) S COUNT=COUNT-1 | 
|---|
| 167 | ;Cache can return the connection status | 
|---|
| 168 | E  I (HLCSTATE("SYSTEM","OS")="CACHE") S HLCSTATE("CONNECTED")=($ZA\8192#2) I 'HLCSTATE("CONNECTED") D CLOSE(.HLCSTATE) | 
|---|
| 169 | ; | 
|---|
| 170 | ;if the <EB> character was encountered, then there are no more segments in the message, set the end of message flag | 
|---|
| 171 | I SUCCESS,SEG(COUNT)[$C(28) D | 
|---|
| 172 | .K SEG | 
|---|
| 173 | .S SUCCESS=0 | 
|---|
| 174 | .S HLCSTATE("MESSAGE ENDED")=1 | 
|---|
| 175 | Q SUCCESS | 
|---|
| 176 | ; | 
|---|
| 177 | READHDR(HLCSTATE,HDR) ; | 
|---|
| 178 | ;reads the next header segment in the message stream, discarding everything that comes before it | 
|---|
| 179 | ; | 
|---|
| 180 | N SEG,SUCCESS,J,I | 
|---|
| 181 | S SUCCESS=0 | 
|---|
| 182 | K HDR | 
|---|
| 183 | F  Q:'$$READSEG(.HLCSTATE,.SEG)  D  Q:SUCCESS | 
|---|
| 184 | .S I=0 | 
|---|
| 185 | .;look for the <SB> | 
|---|
| 186 | .;perhaps the <SB> isn't in the first line | 
|---|
| 187 | .F  S I=$O(SEG(I)) Q:'I  D  Q:SUCCESS | 
|---|
| 188 | ..I (SEG(I)'[$C(11)) K SEG(I) Q | 
|---|
| 189 | ..S SEG(I)=$P(SEG(I),$C(11),2) | 
|---|
| 190 | ..S SUCCESS=1 | 
|---|
| 191 | ..K:SEG(I)="" SEG(I) | 
|---|
| 192 | I SUCCESS S (I,J)=0 F  S J=$O(SEG(J)) Q:'J  S I=I+1,HDR(I)=SEG(J) | 
|---|
| 193 | Q SUCCESS | 
|---|
| 194 | ; | 
|---|
| 195 | CLOSE(HLCSTATE) ; | 
|---|
| 196 | CLOSE HLCSTATE("DEVICE") | 
|---|
| 197 | Q | 
|---|
| 198 | ; | 
|---|
| 199 | ENDMSG(HLCSTATE)        ; | 
|---|
| 200 | N SEG | 
|---|
| 201 | S SEG(1)=$C(28) | 
|---|
| 202 | I $$WRITESEG(.HLCSTATE,.SEG) D  Q 1 | 
|---|
| 203 | .D FLUSH | 
|---|
| 204 | .U HLCSTATE("DEVICE") | 
|---|
| 205 | .I ('$G(HLCSTATE("FLUSHED")))!$X W @HLCSTATE("FLUSH") S HLCSTATE("FLUSHED")=1 | 
|---|
| 206 | Q 0 | 
|---|