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