| 1 | HLCSTCP1 ;SFIRMFO/RSD - BI-DIRECTIONAL TCP ;10/17/2007  12:59 | 
|---|
| 2 | ;;1.6;HEALTH LEVEL SEVEN;**19,43,57,64,71,133,132,122**;OCT 13,1995;Build 14 | 
|---|
| 3 | ;Per VHA Directive 2004-038, this routine should not be modified. | 
|---|
| 4 | ;Receiver | 
|---|
| 5 | ;connection is initiated by sender and listener accepts connection | 
|---|
| 6 | ;and calls this routine | 
|---|
| 7 | ; | 
|---|
| 8 | N $ETRAP,$ESTACK S $ETRAP="D ERROR^HLCSTCP1" | 
|---|
| 9 | N HLMIEN,HLASTMSG | 
|---|
| 10 | ; | 
|---|
| 11 | ; patch HL*1.6*122 start | 
|---|
| 12 | ; variable to replace ^TMP | 
|---|
| 13 | N HLTMBUF | 
|---|
| 14 | ; | 
|---|
| 15 | ; for HL7 application proxy user | 
|---|
| 16 | ;; N HLDUZ,DUZ  ; patch HL*1.6*122 TEST v2: DUZ code removed | 
|---|
| 17 | N HLDUZ | 
|---|
| 18 | S HLDUZ=+$G(DUZ) | 
|---|
| 19 | ; | 
|---|
| 20 | D MON^HLCSTCP("Open") | 
|---|
| 21 | ; K ^TMP("HLCSTCP",$J,0) | 
|---|
| 22 | S HLMIEN=0,HLASTMSG="" | 
|---|
| 23 | ; | 
|---|
| 24 | ; patch HL*1.6*122 TEST v2: DUZ code removed | 
|---|
| 25 | ; set DUZ for application proxy user | 
|---|
| 26 | ;; D PROXY^HLCSTCP4 | 
|---|
| 27 | ; | 
|---|
| 28 | F  D  Q:$$STOP^HLCSTCP  I 'HLMIEN D MON^HLCSTCP("Idle") H 3 | 
|---|
| 29 | . ; clean variables | 
|---|
| 30 | . D CLEANVAR^HLCSTCP4 | 
|---|
| 31 | . S HLMIEN=$$READ | 
|---|
| 32 | . Q:'HLMIEN | 
|---|
| 33 | . ; | 
|---|
| 34 | . ; patch HL*1.6*122 TEST v2: DUZ code removed | 
|---|
| 35 | . ; DUZ comparison/reset for application proxy user | 
|---|
| 36 | . ;; D HLDUZ^HLCSTCP4 | 
|---|
| 37 | . D HLDUZ2^HLCSTCP4 | 
|---|
| 38 | . ; protect HLDUZ | 
|---|
| 39 | . N HLDUZ | 
|---|
| 40 | . D PROCESS | 
|---|
| 41 | ; patch HL*1.6*122 end | 
|---|
| 42 | Q | 
|---|
| 43 | ; | 
|---|
| 44 | PROCESS ;check message and reply | 
|---|
| 45 | ;HLDP=LL in 870 | 
|---|
| 46 | N HLTCP,HLTCPI,HLTCPO | 
|---|
| 47 | S HLTCP="",HLTCPO=HLDP,HLTCPI=+HLMIEN | 
|---|
| 48 | ;update monitor, msg. received | 
|---|
| 49 | D LLCNT^HLCSTCP(HLDP,1) | 
|---|
| 50 | D NEW^HLTP3(HLMIEN) | 
|---|
| 51 | ;update monitor, msg. processed | 
|---|
| 52 | D LLCNT^HLCSTCP(HLDP,2) | 
|---|
| 53 | Q | 
|---|
| 54 | ; | 
|---|
| 55 | READ() ;read 1 message, returns ien in 773^ien in 772 for message | 
|---|
| 56 | D MON^HLCSTCP("Reading") | 
|---|
| 57 | N HLDB,HLDT,HLDEND,HLACKWT,HLDSTRT,HLHDR,HLIND1,HLINE,HLMSG,HLRDOUT,HLRS,HLX,X | 
|---|
| 58 | ;HLDSTRT=start char., HLDEND=end char., HLRS=record seperator | 
|---|
| 59 | S HLDSTRT=$C(11),HLDEND=$C(28),HLRS=$C(13) | 
|---|
| 60 | ;HLRDOUT=exit read loop, HLINE=line count, HLIND1=ien 773^ien 772 | 
|---|
| 61 | ;HLHDR=have a header, HLTMBUF()=excess from last read, HLACKWT=wait for ack | 
|---|
| 62 | ; HL*1.6*122 start | 
|---|
| 63 | ; S (HLRDOUT,HLINE,HLIND1,HLHDR)=0,HLX=$G(^TMP("HLCSTCP",$J,0)),HLACKWT=HLDBACK | 
|---|
| 64 | S (HLRDOUT,HLINE,HLIND1,HLHDR)=0,HLX=$G(HLTMBUF(0)),HLACKWT=HLDBACK | 
|---|
| 65 | N HLBUFF,HLXX,MAXWAIT | 
|---|
| 66 | ; based on patch 132 for readtime | 
|---|
| 67 | S MAXWAIT=$S((HLACKWT>HLDREAD):HLACKWT,1:HLDREAD) | 
|---|
| 68 | S HLRS("START-FLAG")=0 | 
|---|
| 69 | S HLTMBUF(0)="" | 
|---|
| 70 | ; variable used to store data in HLBUFF | 
|---|
| 71 | S HLX(1)=$G(HLTMBUF(1)) | 
|---|
| 72 | S HLTMBUF(1)="" | 
|---|
| 73 | S HLBUFF("START")=0 | 
|---|
| 74 | S HLBUFF("END")=0 | 
|---|
| 75 | I (HLX]"")!(HLX(1)]"") D | 
|---|
| 76 | . I (HLX[HLDSTRT)!(HLX(1)[HLDSTRT) D | 
|---|
| 77 | .. S HLBUFF("START")=1 | 
|---|
| 78 | . I (HLX[HLDEND)!(HLX(1)[HLDEND) D | 
|---|
| 79 | .. S HLBUFF("END")=1 | 
|---|
| 80 | F  D RDBLK Q:HLRDOUT | 
|---|
| 81 | ;**132** | 
|---|
| 82 | ;switch to null device if opened to prevent 'leakage' | 
|---|
| 83 | I $G(IO(0))]"",IO(0)'=IO U IO(0) | 
|---|
| 84 | ; | 
|---|
| 85 | ;save any excess for next time | 
|---|
| 86 | S:HLX]"" HLTMBUF(0)=HLX | 
|---|
| 87 | S:HLX(1)]"" HLTMBUF(1)=HLX(1) | 
|---|
| 88 | I +HLIND1,'$P(HLIND1,U,3) D DELMSG(HLIND1) S HLIND1=0 | 
|---|
| 89 | Q HLIND1 | 
|---|
| 90 | ; | 
|---|
| 91 | RDBLK ; | 
|---|
| 92 | ; initialize | 
|---|
| 93 | S HLBUFF="" | 
|---|
| 94 | ; | 
|---|
| 95 | ;S HLDB=HLDBSIZE-$L(HLX) | 
|---|
| 96 | ; store the total length of HLX and HLX(1) in HLDB(1) | 
|---|
| 97 | S HLDB(1)=$L(HLX)+$L(HLX(1)) | 
|---|
| 98 | ; | 
|---|
| 99 | ;**132 ** | 
|---|
| 100 | ;U IO R X#HLDB:HLDREAD | 
|---|
| 101 | ; U IO R X#HLDB:MAXWAIT | 
|---|
| 102 | ; | 
|---|
| 103 | ; remove the readcount to speedup GT.M | 
|---|
| 104 | U IO | 
|---|
| 105 | R:(HLDB(1)<HLDBSIZE) HLBUFF:MAXWAIT | 
|---|
| 106 | I HLBUFF]"" D | 
|---|
| 107 | . I HLBUFF[HLDSTRT,(HLBUFF("START")=0) D | 
|---|
| 108 | .. ; remove the extraneous text prefixing the "START" char | 
|---|
| 109 | .. I $P(HLBUFF,HLDSTRT)]"" S HLBUFF=HLDSTRT_$P(HLBUFF,HLDSTRT,2,99) | 
|---|
| 110 | .. S HLBUFF("START")=1 | 
|---|
| 111 | . ; | 
|---|
| 112 | . I HLBUFF[HLDEND,(HLBUFF("END")=0) S HLBUFF("END")=1 | 
|---|
| 113 | ; detect disconnect for GT.M | 
|---|
| 114 | I $G(^%ZOSF("OS"))["GT.M",$DEVICE S $ECODE=",UREAD," | 
|---|
| 115 | ; timedout, <clean up>, quit | 
|---|
| 116 | ;I '$T,X="",HLX="" S HLACKWT=HLACKWT-HLDREAD D:HLACKWT<0&'HLHDR CLEAN Q | 
|---|
| 117 | ;I '$T,X="",HLX="" D:'HLHDR CLEAN Q | 
|---|
| 118 | I '$T,HLBUFF="",HLX="",HLX(1)="" D  Q | 
|---|
| 119 | . D:('HLHDR)&('HLIND1) CLEAN | 
|---|
| 120 | ;add incoming line to what wasn't processed in last read | 
|---|
| 121 | ;S HLX=$G(HLX)_X | 
|---|
| 122 | ; | 
|---|
| 123 | ; get block of characters from read buffer HLBUFF | 
|---|
| 124 | ; every 'for-loop' deal with one read at most, and one message at most | 
|---|
| 125 | ; if HLX is not empty, loop continues even no data is read | 
|---|
| 126 | ; quit, if both HLDBUFF and HLX(1) are empty, means one read is done | 
|---|
| 127 | ; quit, when HLRDOUT is set to 1, means one message is encountered | 
|---|
| 128 | ; an "end" | 
|---|
| 129 | ; F  D  Q:HLXX=""!(HLRDOUT) | 
|---|
| 130 | F  D  Q:(HLRDOUT)!(HLBUFF=""&(HLX(1)="")) | 
|---|
| 131 | . ; | 
|---|
| 132 | . ; if HLX(1) is not empty | 
|---|
| 133 | . I HLX(1)]"" D | 
|---|
| 134 | .. ; hldb(2) is the number of characters extracted from hlx(1) | 
|---|
| 135 | .. ; to be concatenated with hlx | 
|---|
| 136 | .. S HLDB(2)=HLDBSIZE-$L(HLX) | 
|---|
| 137 | .. ; hlx(2) stores the first hldb(2) characters extracted | 
|---|
| 138 | .. ; from hlx(1) | 
|---|
| 139 | .. S HLX(2)=$E(HLX(1),1,HLDB(2)) | 
|---|
| 140 | .. S HLX(1)=$E(HLX(1),HLDB(2)+1,$L(HLX(1))) | 
|---|
| 141 | .. S HLX=$G(HLX)_HLX(2) | 
|---|
| 142 | . ; | 
|---|
| 143 | . ; if HLX(1) is empty, and HLBUFF contains data | 
|---|
| 144 | . ; all the data in hlx(1) need to be extracted first | 
|---|
| 145 | . I HLX(1)="",HLBUFF]"" D | 
|---|
| 146 | .. S HLDB=HLDBSIZE-$L(HLX) | 
|---|
| 147 | .. S HLXX=$E(HLBUFF,1,HLDB) | 
|---|
| 148 | .. S HLBUFF=$E(HLBUFF,HLDB+1,$L(HLBUFF)) | 
|---|
| 149 | .. S HLX=$G(HLX)_HLXX | 
|---|
| 150 | . ; quit when HLX is empty | 
|---|
| 151 | . Q:(HLX="") | 
|---|
| 152 | . ; ** 132 ** | 
|---|
| 153 | . ; if no segment end, HLX not full, go back for more | 
|---|
| 154 | . I $L(HLX)<HLDBSIZE,HLX'[HLRS,HLX'[HLDEND Q | 
|---|
| 155 | . ;add incoming line to what wasn't processed | 
|---|
| 156 | . D RDBLK2 | 
|---|
| 157 | ; | 
|---|
| 158 | ; it is possible one message is encountered an "end" and other | 
|---|
| 159 | ; messages left in buffer,HLBUFF, save it in HLX for next run | 
|---|
| 160 | I HLBUFF]"" D | 
|---|
| 161 | . ; variable HLBUFF may remain data with size more than HLDBSIZE | 
|---|
| 162 | . ; variable HLBUFF is not empty, only if the total length of | 
|---|
| 163 | . ; HLX and HLX(1) is less than HLDBSIZE and HLX(1) should be | 
|---|
| 164 | . ; empty when the command s hlx(1)=$g(hlx(1))_hlbuff is executed | 
|---|
| 165 | . ; use hlx(1) to store the data of hlbuff to avoid "MAXTRING" error | 
|---|
| 166 | . S HLX(1)=$G(HLX(1))_HLBUFF | 
|---|
| 167 | . S HLBUFF="" | 
|---|
| 168 | Q | 
|---|
| 169 | ; | 
|---|
| 170 | RDBLK2 ;data stream: <sb>dddd<cr><eb><cr> | 
|---|
| 171 | ; HL*1.6*122 end | 
|---|
| 172 | ; look for segment= <CR> | 
|---|
| 173 | F  Q:HLX'[HLRS  D  Q:HLRDOUT | 
|---|
| 174 | . ; Get the first piece, save the rest of the line | 
|---|
| 175 | . S HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLRS),HLX=$P(HLX,HLRS,2,999) | 
|---|
| 176 | . ; check for start block, Quit if no ien | 
|---|
| 177 | . I HLMSG(HLINE,0)[HLDSTRT!HLHDR D  Q | 
|---|
| 178 | .. S HLRS("START-FLAG")=1 ; HL*1.6*122 | 
|---|
| 179 | .. D:HLMSG(HLINE,0)[HLDSTRT | 
|---|
| 180 | ... S X=$L(HLMSG(HLINE,0),HLDSTRT) | 
|---|
| 181 | ... S:X>2 HLMSG(HLINE,0)=HLDSTRT_$P(HLMSG(HLINE,0),HLDSTRT,X) | 
|---|
| 182 | ... S HLMSG(HLINE,0)=$P(HLMSG(HLINE,0),HLDSTRT,2) | 
|---|
| 183 | ... D RESET:(HLINE>1) | 
|---|
| 184 | .. ; | 
|---|
| 185 | .. ; patch HL*1.6*122 | 
|---|
| 186 | .. ; if the first line less than 10 characters | 
|---|
| 187 | .. I HLHDR,$L(HLMSG(1,0))<10,$D(HLMSG(2,0)) D | 
|---|
| 188 | ... S HLMSG(1,0)=HLMSG(1,0)_$E(HLMSG(2,0),1,10) | 
|---|
| 189 | ... S HLMSG(2,0)=$E(HLMSG(2,0),11,9999999) | 
|---|
| 190 | .. ; | 
|---|
| 191 | .. ;ping message | 
|---|
| 192 | .. I $E(HLMSG(1,0),1,9)="MSH^PING^" D PING Q | 
|---|
| 193 | .. ; get next ien to store | 
|---|
| 194 | .. D MIEN^HLCSTCP4 | 
|---|
| 195 | .. K HLMSG | 
|---|
| 196 | .. S (HLINE,HLHDR)=0 | 
|---|
| 197 | . ; check for end block; <eb><cr> | 
|---|
| 198 | . I HLMSG(HLINE,0)[HLDEND D | 
|---|
| 199 | .. ; patch HL*1.6*122 start | 
|---|
| 200 | .. ;no msg. ien | 
|---|
| 201 | .. ; Q:'HLIND1 | 
|---|
| 202 | .. I 'HLIND1 D CLEAN Q | 
|---|
| 203 | .. ; Kill just the last line if no data before HLDEND | 
|---|
| 204 | .. I $P(HLMSG(HLINE,0),HLDEND)']"" D | 
|---|
| 205 | ... K HLMSG(HLINE,0) S HLINE=HLINE-1 | 
|---|
| 206 | .. E  S HLMSG(HLINE,0)=$P(HLMSG(HLINE,0),HLDEND) | 
|---|
| 207 | .. ; patch HL*1.6*122 end | 
|---|
| 208 | .. ; | 
|---|
| 209 | .. ; move into 772 | 
|---|
| 210 | .. D SAVE(.HLMSG,"^HL(772,"_+$P(HLIND1,U,2)_",""IN"")") | 
|---|
| 211 | .. ;mark that end block has been received | 
|---|
| 212 | .. ;HLIND1=ien in 773^ien in 772^1 if end block was received | 
|---|
| 213 | .. S $P(HLIND1,U,3)=1 | 
|---|
| 214 | .. S HLBUFF("HLIND1")=HLIND1 | 
|---|
| 215 | .. ;reset variables for next message | 
|---|
| 216 | .. D CLEAN | 
|---|
| 217 | . ;add blank line for carriage return | 
|---|
| 218 | . I HLINE'=0,HLMSG(HLINE,0)]"" S HLINE=HLINE+1,HLMSG(HLINE,0)="" | 
|---|
| 219 | Q:HLRDOUT | 
|---|
| 220 | ;If the line is long and no <CR> move it into the array. | 
|---|
| 221 | I ($L(HLX)=HLDBSIZE),(HLX'[HLRS),(HLX'[HLDEND),(HLX'[HLDSTRT) D  Q | 
|---|
| 222 | . S HLINE=HLINE+1,HLMSG(HLINE,0)=HLX,HLX="" | 
|---|
| 223 | ;have start block but no record seperator | 
|---|
| 224 | I HLX[HLDSTRT D  Q | 
|---|
| 225 | . ;check for more than 1 start block | 
|---|
| 226 | . S X=$L(HLX,HLDSTRT) S:X>2 HLX=HLDSTRT_$P(HLX,HLDSTRT,X) | 
|---|
| 227 | . ; | 
|---|
| 228 | . ; patch HL*1.6*122 | 
|---|
| 229 | . ; S:$L($P(HLX,HLDSTRT,2))>8 HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLDSTRT,2),HLX="",HLHDR=1 | 
|---|
| 230 | . S HLINE=HLINE+1,HLMSG(HLINE,0)=$P(HLX,HLDSTRT,2),HLX="",HLHDR=1 | 
|---|
| 231 | . ; | 
|---|
| 232 | . D RESET:(HLHDR&(HLINE>1)) | 
|---|
| 233 | ;if no ien, reset | 
|---|
| 234 | ; patch HL*1.6*122 | 
|---|
| 235 | ; I 'HLIND1 D CLEAN Q | 
|---|
| 236 | I (HLRS("START-FLAG")=1),'HLIND1 D CLEAN Q | 
|---|
| 237 | ; big message-merge from local to global every 100 lines | 
|---|
| 238 | I (HLINE-$O(HLMSG(0)))>100 D | 
|---|
| 239 | . M ^HL(772,+$P(HLIND1,U,2),"IN")=HLMSG | 
|---|
| 240 | . ; reset working array | 
|---|
| 241 | . K HLMSG | 
|---|
| 242 | Q | 
|---|
| 243 | ; | 
|---|
| 244 | SAVE(SRC,DEST) ;save into global & set top node | 
|---|
| 245 | ;SRC=source array (passed by ref.), DEST=destination global | 
|---|
| 246 | ; | 
|---|
| 247 | ; patch HL*1.6*122: MPI-client/server | 
|---|
| 248 | I DEST["HLMA" D | 
|---|
| 249 | . F  L +^HLMA(+HLIND1):10 Q:$T  H 1 | 
|---|
| 250 | E  D | 
|---|
| 251 | . F  L +^HL(772,+$P(HLIND1,U,2)):10 Q:$T  H 1 | 
|---|
| 252 | ; | 
|---|
| 253 | M @DEST=SRC | 
|---|
| 254 | S @DEST@(0)="^^"_HLINE_"^"_HLINE_"^"_DT_"^" | 
|---|
| 255 | ; | 
|---|
| 256 | I DEST["HLMA" L -^HLMA(+HLIND1) | 
|---|
| 257 | E  L -^HL(772,+$P(HLIND1,U,2)) | 
|---|
| 258 | ; | 
|---|
| 259 | Q | 
|---|
| 260 | ; | 
|---|
| 261 | DELMSG(HLMAMT) ;delete message from Message Administration/Message Text files. | 
|---|
| 262 | N DIK,DA | 
|---|
| 263 | S DA=+HLMAMT,DIK="^HLMA(" | 
|---|
| 264 | D ^DIK | 
|---|
| 265 | S DA=$P(HLMAMT,U,2),DIK="^HL(772," | 
|---|
| 266 | D ^DIK | 
|---|
| 267 | Q | 
|---|
| 268 | PING ;process PING message | 
|---|
| 269 | S X=HLMSG(1,0) | 
|---|
| 270 | I X[HLDEND U IO W X,! D | 
|---|
| 271 | . ; switch to null device if opened to prevent 'leakage' | 
|---|
| 272 | . I $G(IO(0))]"",$G(IO(0))'=IO U IO(0) | 
|---|
| 273 | CLEAN ;reset var. for next message | 
|---|
| 274 | K HLMSG | 
|---|
| 275 | S HLINE=0,HLRDOUT=1 | 
|---|
| 276 | Q | 
|---|
| 277 | ; | 
|---|
| 278 | ERROR ; Error trap for disconnect error and return back to the read loop. | 
|---|
| 279 | ; patch HL*1.6*122 | 
|---|
| 280 | ; move to routine HLCSTCP4 (splitted-size over 10000) | 
|---|
| 281 | D ERROR1^HLCSTCP4 | 
|---|
| 282 | Q | 
|---|
| 283 | ; | 
|---|
| 284 | CC(X) ;cleanup and close | 
|---|
| 285 | D MON^HLCSTCP(X) | 
|---|
| 286 | H 2 | 
|---|
| 287 | Q | 
|---|
| 288 | RESET ;reset info as a result of no end block | 
|---|
| 289 | N % | 
|---|
| 290 | S HLMSG(1,0)=HLMSG(HLINE,0) | 
|---|
| 291 | F %=2:1:HLINE K HLMSG(%,0) | 
|---|
| 292 | S HLINE=1 | 
|---|
| 293 | Q | 
|---|