| 1 | HLCSTCP ;SFIRMFO/TNV-ALB/JFP,PKE - (TCP/IP) MLLP ;09/19/2007  10:21 | 
|---|
| 2 | ;;1.6;HEALTH LEVEL SEVEN;**19,43,49,57,58,64,84,109,133,122**;Oct 13, 1995;Build 14 | 
|---|
| 3 | ;Per VHA Directive 2004-038, this routine should not be modified. | 
|---|
| 4 | ; | 
|---|
| 5 | ; This is an implementation of the HL7 Minimal Lower Layer Protocol | 
|---|
| 6 | ; taskman entry/startup option, HLDP defined in menu entry. | 
|---|
| 7 | ; | 
|---|
| 8 | Q:'$D(HLDP) | 
|---|
| 9 | ; patch HL*1.6*122 start | 
|---|
| 10 | L +^HLCS("HLTCPLINK",HLDP):5 I '$T D  Q | 
|---|
| 11 | . D MON^HLCSTCP("TskLcked") | 
|---|
| 12 | N HLCSOUT,HLDBACK,HLDBSIZE,HLDREAD,HLDRETR,HLRETRA,HLDWAIT,HLOS,HLTCPADD,HLTCPCS,HLTCPLNK,HLTCPORT,HLTCPRET | 
|---|
| 13 | N HLZRULE | 
|---|
| 14 | ;HLCSOUT= 1-error | 
|---|
| 15 | I '$$INIT D EXITS("Init Error") Q | 
|---|
| 16 | S HLDP("$J")=$J | 
|---|
| 17 | S HLDP("$J",0,"LENGTH")=$L(HLDP("$J")) | 
|---|
| 18 | ; Start the client | 
|---|
| 19 | I $G(HLTCPCS)="C" D  Q | 
|---|
| 20 | . S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-8+$L(HLTCPORT)+$L(HLDP) | 
|---|
| 21 | . I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 | 
|---|
| 22 | . S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) | 
|---|
| 23 | . ; identify process for ^%SY | 
|---|
| 24 | . ; D SETNM^%ZOSV($E("HLClnt:"_HLDP,1,15)) | 
|---|
| 25 | . D SETNM^%ZOSV($E("HLc:"_HLTCPORT_"-"_HLDP_"-"_HLDP("$J",0),1,15)) | 
|---|
| 26 | . K HLDP("$J",0) | 
|---|
| 27 | . D ST1 | 
|---|
| 28 | . F  D ^HLCSTCP2 Q:$$STOP!$G(HLCSOUT) | 
|---|
| 29 | . ; I $G(HLCSOUT)=1 D MON("Error") H 1 Q | 
|---|
| 30 | . I $G(HLCSOUT)=1 D  Q | 
|---|
| 31 | .. D MON("Error") H 1 | 
|---|
| 32 | .. L -^HLCS("HLTCPLINK",HLDP) | 
|---|
| 33 | . I $G(HLCSOUT)=2 D EXITS("Inactive") Q | 
|---|
| 34 | . D EXITS("Shutdown") | 
|---|
| 35 | ; | 
|---|
| 36 | S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-9+$L(HLTCPORT) | 
|---|
| 37 | I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 | 
|---|
| 38 | S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) | 
|---|
| 39 | ; identify process for ^%SY | 
|---|
| 40 | ; D SETNM^%ZOSV($E("HLSrv:"_HLDP,1,15)) | 
|---|
| 41 | D SETNM^%ZOSV($E("HLs:"_HLTCPORT_"-"_HLDP("$J",0),1,15)) | 
|---|
| 42 | K HLDP("$J",0) | 
|---|
| 43 | ; to stop the listener via updated Kernel API, need to pass the | 
|---|
| 44 | ; listener logical link (HLDP) | 
|---|
| 45 | S HLZRULE="S HLDP="_HLDP_" S ZISQUIT=$$STOP^HLCSTCP" | 
|---|
| 46 | ;single threaded listener | 
|---|
| 47 | I $G(HLTCPCS)="S" D  Q | 
|---|
| 48 | . D ST1,MON("Listen"),LISTEN^%ZISTCP(HLTCPORT,"SERVER^HLCSTCP("""_HLDP_""")",HLZRULE) | 
|---|
| 49 | . I $$STOP D EXITS("Shutdown") Q | 
|---|
| 50 | . D EXITS("Openfail") | 
|---|
| 51 | ; | 
|---|
| 52 | ;multi-threaded listener (for OpenM/NT) | 
|---|
| 53 | I ($G(HLTCPCS)'="M")!(^%ZOSF("OS")'["OpenM") D  Q | 
|---|
| 54 | . L -^HLCS("HLTCPLINK",HLDP) | 
|---|
| 55 | I $$OS^%ZOSV["VMS" L -^HLCS("HLTCPLINK",HLDP) Q | 
|---|
| 56 | D ST1,MON("Listen"),LISTEN^%ZISTCPS(HLTCPORT,"SERVERS^HLCSTCP("""_HLDP_""")",HLZRULE) | 
|---|
| 57 | ; update status of listener | 
|---|
| 58 | I $$STOP D EXITS("Shutdown") Q | 
|---|
| 59 | D EXITS("Openfail") | 
|---|
| 60 | ; HL*1.6*122 end | 
|---|
| 61 | Q | 
|---|
| 62 | ; | 
|---|
| 63 | SERVER(HLDP) ; single server using Taskman | 
|---|
| 64 | I '$$INIT D EXITS("Init error") Q | 
|---|
| 65 | D ^HLCSTCP1 | 
|---|
| 66 | I $$STOP D CLOSE^%ZISTCP,EXITS("Shutdown") S IO("C")="" Q | 
|---|
| 67 | Q:$G(HLCSOUT)=1 | 
|---|
| 68 | D MON("Idle") | 
|---|
| 69 | Q | 
|---|
| 70 | ; | 
|---|
| 71 | SERVERS(HLDP) ; Multi-threaded server using Taskman | 
|---|
| 72 | I '$$INIT D EXITS("Init error") Q | 
|---|
| 73 | G LISTEN | 
|---|
| 74 | ; | 
|---|
| 75 | ;multiple process servers, called from an external utility | 
|---|
| 76 | MSM ;MSM entry point, called from User-Defined Services | 
|---|
| 77 | ;HLDP=ien in the HL LOWER LEVEL PROTOCOL PARAMETER file for the | 
|---|
| 78 | ;HL7 Multi-Threaded SERVER | 
|---|
| 79 | S (IO,IO(0))=$P | 
|---|
| 80 | G LISTEN | 
|---|
| 81 | ; | 
|---|
| 82 | LISTEN ; | 
|---|
| 83 | N HLLSTN,HLCSOUT,HLDBACK,HLDBSIZE,HLDREAD,HLDRETR,HLRETRA,HLDWAIT,HLOS,HLTCPADD,HLTCPCS,HLTCPLNK,HLTCPORT,HLTCPRET | 
|---|
| 84 | I '$$INIT D ^%ZTER Q | 
|---|
| 85 | ; patch HL*1.6*122 start | 
|---|
| 86 | S HLDP("$J")=$J | 
|---|
| 87 | S HLDP("$J",0,"LENGTH")=$L(HLDP("$J")) | 
|---|
| 88 | S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-9+$L(HLTCPORT) | 
|---|
| 89 | I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 | 
|---|
| 90 | S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) | 
|---|
| 91 | ; identify process for ^%SY | 
|---|
| 92 | ; D SETNM^%ZOSV($E("HLSrv:"_HLDP,1,15)) | 
|---|
| 93 | D SETNM^%ZOSV($E("HLs:"_HLTCPORT_"-"_HLDP("$J",0),1,15)) | 
|---|
| 94 | K HLDP("$J",0) | 
|---|
| 95 | ; patch HL*1.6*122 end | 
|---|
| 96 | ;HLLSTN used to identify a listener to tag MON | 
|---|
| 97 | S HLLSTN=1 | 
|---|
| 98 | ;increment job count, run server | 
|---|
| 99 | D UPDT(1),^HLCSTCP1,EXITM | 
|---|
| 100 | Q | 
|---|
| 101 | ; | 
|---|
| 102 | DCOPEN(HLDP) ;open direct connect - called from HLMA2 | 
|---|
| 103 | Q:'$$INIT 0 | 
|---|
| 104 | Q:HLTCPADD=""!(HLTCPORT="") 0 | 
|---|
| 105 | Q:'$$OPEN^HLCSTCP2 0 | 
|---|
| 106 | Q 1 | 
|---|
| 107 | ; | 
|---|
| 108 | INIT() ; Initialize Variables | 
|---|
| 109 | ; HLDP should be set to the IEN or name of Logical Link, file 870 | 
|---|
| 110 | S HLOS=$P($G(^%ZOSF("OS")),"^") | 
|---|
| 111 | N DA,DIQUIET,DR,TMP,X,Y | 
|---|
| 112 | S IOF=$$FLUSHCHR^%ZISTCP ; HL*1.6*122 set device flush character | 
|---|
| 113 | S DIQUIET=1 | 
|---|
| 114 | D DT^DICRW | 
|---|
| 115 | I 'HLDP S HLDP=$O(^HLCS(870,"B",HLDP,0)) I 'HLDP Q 0 | 
|---|
| 116 | S DA=HLDP | 
|---|
| 117 | ; patch HL*1.6*122 for field 400.09 | 
|---|
| 118 | S DR="200.02;200.021;200.022;200.03;200.04;200.05;200.09;400.01;400.02;400.03;400.04;400.05;400.09" | 
|---|
| 119 | D GETS^DIQ(870,DA,DR,"IN","TMP","TMP") | 
|---|
| 120 | ; | 
|---|
| 121 | I $D(TMP("DIERR")) QUIT 0 | 
|---|
| 122 | ; -- re-transmit attempts | 
|---|
| 123 | S HLDRETR=+$G(TMP(870,DA_",",200.02,"I")) | 
|---|
| 124 | S HLDRETR("CLOSE")=+$G(TMP(870,DA_",",200.022,"I")) | 
|---|
| 125 | ; -- exceed re-transmit action | 
|---|
| 126 | S HLRETRA=$G(TMP(870,DA_",",200.021,"I")) | 
|---|
| 127 | ; -- block size | 
|---|
| 128 | S HLDBSIZE=+$G(TMP(870,DA_",",200.03,"I")) | 
|---|
| 129 | ; -- read timeout | 
|---|
| 130 | S HLDREAD=+$G(TMP(870,DA_",",200.04,"I")) | 
|---|
| 131 | ; -- ack timeout | 
|---|
| 132 | S HLDBACK=+$G(TMP(870,DA_",",200.05,"I")) | 
|---|
| 133 | ; -- uni-directional wait | 
|---|
| 134 | S HLDWAIT=$G(TMP(870,DA_",",200.09,"I")) | 
|---|
| 135 | ; -- tcp address | 
|---|
| 136 | S HLTCPADD=$G(TMP(870,DA_",",400.01,"I")) | 
|---|
| 137 | ; -- tcp port | 
|---|
| 138 | S HLTCPORT=$G(TMP(870,DA_",",400.02,"I")) | 
|---|
| 139 | ; -- tcp/ip service type | 
|---|
| 140 | S HLTCPCS=$G(TMP(870,DA_",",400.03,"I")) | 
|---|
| 141 | ; -- link persistence | 
|---|
| 142 | S HLTCPLNK=$G(TMP(870,DA_",",400.04,"I")) | 
|---|
| 143 | ; -- retention | 
|---|
| 144 | S HLTCPRET=$G(TMP(870,DA_",",400.05,"I")) | 
|---|
| 145 | ; | 
|---|
| 146 | ; patch HL*1.6*122 for field 400.09 | 
|---|
| 147 | ; -- tcp/ip openfail timeout | 
|---|
| 148 | S HLTCPLNK("TIMEOUT")=$G(TMP(870,DA_",",400.09,"I")) | 
|---|
| 149 | ; | 
|---|
| 150 | ; -- set defaults in case something's not set | 
|---|
| 151 | S:HLDREAD=0 HLDREAD=10 | 
|---|
| 152 | S:HLDBACK=0 HLDBACK=60 | 
|---|
| 153 | ; patch HL*1.6*122 | 
|---|
| 154 | ; S:HLDBSIZE=0 HLDBSIZE=245 | 
|---|
| 155 | S:HLDBSIZE<245 HLDBSIZE=245 | 
|---|
| 156 | S:HLDRETR=0 HLDRETR=5 | 
|---|
| 157 | S:HLTCPRET="" X=$P($$PARAM^HLCS2,U,12),HLTCPRET=$S(X:X,1:15) | 
|---|
| 158 | ; | 
|---|
| 159 | ; patch HL*1.6*122 for field 400.09 | 
|---|
| 160 | S:HLTCPLNK("TIMEOUT")=0 HLTCPLNK("TIMEOUT")=5 | 
|---|
| 161 | ; | 
|---|
| 162 | Q 1 | 
|---|
| 163 | ; | 
|---|
| 164 | ST1 ;record startup in 870 for single server | 
|---|
| 165 | ;4=status 9=Time Started, 10=Time Stopped, 11=Task Number | 
|---|
| 166 | ;14=Shutdown LLP, 3=LLP Online, 18=Gross Errors | 
|---|
| 167 | N HLJ,X | 
|---|
| 168 | ; HL*1.6*122 remove unnecessary locks | 
|---|
| 169 | ;F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 170 | S X="HLJ(870,"""_HLDP_","")" | 
|---|
| 171 | S @X@(4)="Init",(@X@(10),@X@(18))="@",@X@(14)=0 | 
|---|
| 172 | I HLTCPCS["C" S @X@(3)=$S(HLTCPLNK["Y":"PC",1:"NC") | 
|---|
| 173 | E  S @X@(3)=$S(HLTCPCS["S":"SS",HLTCPCS["M":"MS",1:"") | 
|---|
| 174 | I @X@(3)'="NC" S @X@(9)=$$NOW^XLFDT | 
|---|
| 175 | S:$G(ZTSK) @X@(11)=ZTSK | 
|---|
| 176 | D FILE^HLDIE("","HLJ","","ST1","HLCSTCP") ;HL*1.6*109 | 
|---|
| 177 | ;L -^HLCS(870,HLDP,0) | 
|---|
| 178 | Q | 
|---|
| 179 | ; | 
|---|
| 180 | MON(Y) ;Display current state & check for shutdown | 
|---|
| 181 | ;don't display for multiple server | 
|---|
| 182 | Q:$G(HLLSTN) | 
|---|
| 183 | ; HL*1.6*122 remove unnecessary locks | 
|---|
| 184 | ;F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 185 | S $P(^HLCS(870,HLDP,0),U,5)=Y | 
|---|
| 186 | ;L -^HLCS(870,HLDP,0) | 
|---|
| 187 | Q:'$D(HLTRACE) | 
|---|
| 188 | N X U IO(0) | 
|---|
| 189 | W !,"IN State: ",Y | 
|---|
| 190 | I '$$STOP D | 
|---|
| 191 | . ; patch HL*1.6*122 | 
|---|
| 192 | . ; R !,"Type Q to Quit: ",X#1:1 | 
|---|
| 193 | . R !,"Type Q to Quit: ",X:1 | 
|---|
| 194 | . ; I $L(X),"Qq"[X S $P(^HLCS(870,HLDP,0),U,15)=1 | 
|---|
| 195 | . I $L(X),"Qq"[$E(X) S $P(^HLCS(870,HLDP,0),U,15)=1 | 
|---|
| 196 | . ; patch HL*1.6*122 end | 
|---|
| 197 | U IO | 
|---|
| 198 | Q | 
|---|
| 199 | UPDT(Y) ;update job count for multiple servers,X=1 increment | 
|---|
| 200 | N HLJ,X | 
|---|
| 201 | ; | 
|---|
| 202 | ; HL*1.6*122 start | 
|---|
| 203 | ; F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 204 | Q:'$G(HLDP) | 
|---|
| 205 | Q:'$D(^HLCS(870,"E","M",HLDP)) | 
|---|
| 206 | F  L +^HLCS(870,HLDP,0):10 Q:$T  H 1 | 
|---|
| 207 | ; S X=+$P(^HLCS(870,HLDP,0),U,5),$P(^(0),U,5)=$S(Y:X+1,1:X-1)_" server" | 
|---|
| 208 | S X=+$P(^HLCS(870,HLDP,0),U,5) | 
|---|
| 209 | I X<0 S X=0 | 
|---|
| 210 | S $P(^HLCS(870,HLDP,0),U,5)=$S(Y:(X+1),X<1:0,1:X-1)_" server" | 
|---|
| 211 | ;if incrementing, set the Device Type field to Multi-Server | 
|---|
| 212 | ; I X S HLJ(870,HLDP_",",3)="MS" D FILE^HLDIE("","HLJ","","UPDT","HLCSTCP") | 
|---|
| 213 | I $P(^HLCS(870,HLDP,0),"^",4)']"" S $P(^HLCS(870,HLDP,0),"^",4)="MS" | 
|---|
| 214 | ; HL*1.6*122 end | 
|---|
| 215 | ; | 
|---|
| 216 | L -^HLCS(870,HLDP,0) | 
|---|
| 217 | Q | 
|---|
| 218 | STOP() ;stop flag set | 
|---|
| 219 | N X | 
|---|
| 220 | F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 221 | S X=+$P(^HLCS(870,HLDP,0),U,15) | 
|---|
| 222 | L -^HLCS(870,HLDP,0) | 
|---|
| 223 | Q X | 
|---|
| 224 | ; | 
|---|
| 225 | LLCNT(DP,Y,Z) ;update Logical Link counters | 
|---|
| 226 | ;DP=ien of Logical Link in file 870 | 
|---|
| 227 | ;Y: 1=msg rec, 2=msg proc, 3=msg to send, 4=msg sent | 
|---|
| 228 | ;Z: ""=add to counter, 1=subtract from counter | 
|---|
| 229 | Q:'$D(^HLCS(870,+$G(DP),0))!('$G(Y)) | 
|---|
| 230 | N P,X | 
|---|
| 231 | S P=$S(Y<3:"IN",1:"OUT")_" QUEUE "_$S(Y#2:"BACK",1:"FRONT")_" POINTER" | 
|---|
| 232 | ; patch HL*1.6*122 start | 
|---|
| 233 | ; F  L +^HLCS(870,DP,P):2 Q:$T | 
|---|
| 234 | ; S X=+$G(^HLCS(870,DP,P)),^(P)=X+$S($G(Z):-1,1:1) | 
|---|
| 235 | I '$L($G(OS)) N OS S OS=$G(^%ZOSF("OS")) | 
|---|
| 236 | I OS'["DSM",OS'["OpenM" D | 
|---|
| 237 | . F  L +^HLCS(870,DP,P):10 Q:$T  H 1 | 
|---|
| 238 | . S X=+$G(^HLCS(870,DP,P)),^(P)=X+$S($G(Z):-1,1:1) | 
|---|
| 239 | . L -^HLCS(870,DP,P) | 
|---|
| 240 | E  D | 
|---|
| 241 | . S X=$I(^HLCS(870,DP,P),$S($G(Z):-1,1:1)) | 
|---|
| 242 | ; L -^HLCS(870,DP,P) | 
|---|
| 243 | ; patch HL*1.6*122 end | 
|---|
| 244 | Q | 
|---|
| 245 | SDFLD ; set Shutdown? field to yes | 
|---|
| 246 | Q:'$G(HLDP) | 
|---|
| 247 | ; HL*1.6*122 remove unnecessary lock and call to FM | 
|---|
| 248 | S $P(^HLCS(870,HLDP,0),U,15)=1 | 
|---|
| 249 | ;N HLJ,X | 
|---|
| 250 | ;F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 251 | ;14=Shutdown LLP? | 
|---|
| 252 | ;S HLJ(870,HLDP_",",14)=1 | 
|---|
| 253 | ;D FILE^HLDIE("","HLJ","","SDFLD","HLCSTCP") ;HL*1.6*109 | 
|---|
| 254 | ;L -^HLCS(870,HLDP,0) | 
|---|
| 255 | Q | 
|---|
| 256 | ; | 
|---|
| 257 | EXITS(Y) ; shutdown and clean up the listener process for either | 
|---|
| 258 | ; single-threaded or multi-threaded | 
|---|
| 259 | N HLJ,X | 
|---|
| 260 | F  L +^HLCS(870,HLDP,0):2 Q:$T | 
|---|
| 261 | ;4=status,10=Time Stopped,9=Time Started,11=Task Number | 
|---|
| 262 | S X="HLJ(870,"""_HLDP_","")" | 
|---|
| 263 | S @X@(4)=Y,@X@(11)="@" | 
|---|
| 264 | S:$G(HLCSOUT)'=2 @X@(10)=$$NOW^XLFDT,@X@(9)="@" | 
|---|
| 265 | D FILE^HLDIE("","HLJ","","EXITS","HLCSTCP") ; HL*1.6*109 | 
|---|
| 266 | L -^HLCS(870,HLDP,0) | 
|---|
| 267 | I $D(ZTQUEUED) S ZTREQ="@" | 
|---|
| 268 | ; HL*1.6*122 | 
|---|
| 269 | L -^HLCS("HLTCPLINK",HLDP) | 
|---|
| 270 | Q | 
|---|
| 271 | ; | 
|---|
| 272 | EXITM ;Multiple service shutdown and clean up | 
|---|
| 273 | ; shutdown and clean up a connection spawned by the listener | 
|---|
| 274 | ; process for a multi-threaded listener | 
|---|
| 275 | D UPDT(0) | 
|---|
| 276 | I $D(ZTQUEUED) S ZTREQ="@" | 
|---|
| 277 | Q | 
|---|