HLCSTCP ;SFIRMFO/TNV-ALB/JFP,PKE - (TCP/IP) MLLP ;09/19/2007 10:21 ;;1.6;HEALTH LEVEL SEVEN;**19,43,49,57,58,64,84,109,133,122**;Oct 13, 1995;Build 14 ;Per VHA Directive 2004-038, this routine should not be modified. ; ; This is an implementation of the HL7 Minimal Lower Layer Protocol ; taskman entry/startup option, HLDP defined in menu entry. ; Q:'$D(HLDP) ; patch HL*1.6*122 start L +^HLCS("HLTCPLINK",HLDP):5 I '$T D Q . D MON^HLCSTCP("TskLcked") N HLCSOUT,HLDBACK,HLDBSIZE,HLDREAD,HLDRETR,HLRETRA,HLDWAIT,HLOS,HLTCPADD,HLTCPCS,HLTCPLNK,HLTCPORT,HLTCPRET N HLZRULE ;HLCSOUT= 1-error I '$$INIT D EXITS("Init Error") Q S HLDP("$J")=$J S HLDP("$J",0,"LENGTH")=$L(HLDP("$J")) ; Start the client I $G(HLTCPCS)="C" D Q . S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-8+$L(HLTCPORT)+$L(HLDP) . I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 . S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) . ; identify process for ^%SY . ; D SETNM^%ZOSV($E("HLClnt:"_HLDP,1,15)) . D SETNM^%ZOSV($E("HLc:"_HLTCPORT_"-"_HLDP_"-"_HLDP("$J",0),1,15)) . K HLDP("$J",0) . D ST1 . F D ^HLCSTCP2 Q:$$STOP!$G(HLCSOUT) . ; I $G(HLCSOUT)=1 D MON("Error") H 1 Q . I $G(HLCSOUT)=1 D Q .. D MON("Error") H 1 .. L -^HLCS("HLTCPLINK",HLDP) . I $G(HLCSOUT)=2 D EXITS("Inactive") Q . D EXITS("Shutdown") ; S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-9+$L(HLTCPORT) I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) ; identify process for ^%SY ; D SETNM^%ZOSV($E("HLSrv:"_HLDP,1,15)) D SETNM^%ZOSV($E("HLs:"_HLTCPORT_"-"_HLDP("$J",0),1,15)) K HLDP("$J",0) ; to stop the listener via updated Kernel API, need to pass the ; listener logical link (HLDP) S HLZRULE="S HLDP="_HLDP_" S ZISQUIT=$$STOP^HLCSTCP" ;single threaded listener I $G(HLTCPCS)="S" D Q . D ST1,MON("Listen"),LISTEN^%ZISTCP(HLTCPORT,"SERVER^HLCSTCP("""_HLDP_""")",HLZRULE) . I $$STOP D EXITS("Shutdown") Q . D EXITS("Openfail") ; ;multi-threaded listener (for OpenM/NT) I ($G(HLTCPCS)'="M")!(^%ZOSF("OS")'["OpenM") D Q . L -^HLCS("HLTCPLINK",HLDP) I $$OS^%ZOSV["VMS" L -^HLCS("HLTCPLINK",HLDP) Q D ST1,MON("Listen"),LISTEN^%ZISTCPS(HLTCPORT,"SERVERS^HLCSTCP("""_HLDP_""")",HLZRULE) ; update status of listener I $$STOP D EXITS("Shutdown") Q D EXITS("Openfail") ; HL*1.6*122 end Q ; SERVER(HLDP) ; single server using Taskman I '$$INIT D EXITS("Init error") Q D ^HLCSTCP1 I $$STOP D CLOSE^%ZISTCP,EXITS("Shutdown") S IO("C")="" Q Q:$G(HLCSOUT)=1 D MON("Idle") Q ; SERVERS(HLDP) ; Multi-threaded server using Taskman I '$$INIT D EXITS("Init error") Q G LISTEN ; ;multiple process servers, called from an external utility MSM ;MSM entry point, called from User-Defined Services ;HLDP=ien in the HL LOWER LEVEL PROTOCOL PARAMETER file for the ;HL7 Multi-Threaded SERVER S (IO,IO(0))=$P G LISTEN ; LISTEN ; N HLLSTN,HLCSOUT,HLDBACK,HLDBSIZE,HLDREAD,HLDRETR,HLRETRA,HLDWAIT,HLOS,HLTCPADD,HLTCPCS,HLTCPLNK,HLTCPORT,HLTCPRET I '$$INIT D ^%ZTER Q ; patch HL*1.6*122 start S HLDP("$J")=$J S HLDP("$J",0,"LENGTH")=$L(HLDP("$J")) S HLDP("$J",0,"START")=HLDP("$J",0,"LENGTH")-9+$L(HLTCPORT) I HLDP("$J",0,"START")<1 S HLDP("$J",0,"START")=1 S HLDP("$J",0)=$E(HLDP("$J"),HLDP("$J",0,"START"),HLDP("$J",0,"LENGTH")) ; identify process for ^%SY ; D SETNM^%ZOSV($E("HLSrv:"_HLDP,1,15)) D SETNM^%ZOSV($E("HLs:"_HLTCPORT_"-"_HLDP("$J",0),1,15)) K HLDP("$J",0) ; patch HL*1.6*122 end ;HLLSTN used to identify a listener to tag MON S HLLSTN=1 ;increment job count, run server D UPDT(1),^HLCSTCP1,EXITM Q ; DCOPEN(HLDP) ;open direct connect - called from HLMA2 Q:'$$INIT 0 Q:HLTCPADD=""!(HLTCPORT="") 0 Q:'$$OPEN^HLCSTCP2 0 Q 1 ; INIT() ; Initialize Variables ; HLDP should be set to the IEN or name of Logical Link, file 870 S HLOS=$P($G(^%ZOSF("OS")),"^") N DA,DIQUIET,DR,TMP,X,Y S IOF=$$FLUSHCHR^%ZISTCP ; HL*1.6*122 set device flush character S DIQUIET=1 D DT^DICRW I 'HLDP S HLDP=$O(^HLCS(870,"B",HLDP,0)) I 'HLDP Q 0 S DA=HLDP ; patch HL*1.6*122 for field 400.09 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" D GETS^DIQ(870,DA,DR,"IN","TMP","TMP") ; I $D(TMP("DIERR")) QUIT 0 ; -- re-transmit attempts S HLDRETR=+$G(TMP(870,DA_",",200.02,"I")) S HLDRETR("CLOSE")=+$G(TMP(870,DA_",",200.022,"I")) ; -- exceed re-transmit action S HLRETRA=$G(TMP(870,DA_",",200.021,"I")) ; -- block size S HLDBSIZE=+$G(TMP(870,DA_",",200.03,"I")) ; -- read timeout S HLDREAD=+$G(TMP(870,DA_",",200.04,"I")) ; -- ack timeout S HLDBACK=+$G(TMP(870,DA_",",200.05,"I")) ; -- uni-directional wait S HLDWAIT=$G(TMP(870,DA_",",200.09,"I")) ; -- tcp address S HLTCPADD=$G(TMP(870,DA_",",400.01,"I")) ; -- tcp port S HLTCPORT=$G(TMP(870,DA_",",400.02,"I")) ; -- tcp/ip service type S HLTCPCS=$G(TMP(870,DA_",",400.03,"I")) ; -- link persistence S HLTCPLNK=$G(TMP(870,DA_",",400.04,"I")) ; -- retention S HLTCPRET=$G(TMP(870,DA_",",400.05,"I")) ; ; patch HL*1.6*122 for field 400.09 ; -- tcp/ip openfail timeout S HLTCPLNK("TIMEOUT")=$G(TMP(870,DA_",",400.09,"I")) ; ; -- set defaults in case something's not set S:HLDREAD=0 HLDREAD=10 S:HLDBACK=0 HLDBACK=60 ; patch HL*1.6*122 ; S:HLDBSIZE=0 HLDBSIZE=245 S:HLDBSIZE<245 HLDBSIZE=245 S:HLDRETR=0 HLDRETR=5 S:HLTCPRET="" X=$P($$PARAM^HLCS2,U,12),HLTCPRET=$S(X:X,1:15) ; ; patch HL*1.6*122 for field 400.09 S:HLTCPLNK("TIMEOUT")=0 HLTCPLNK("TIMEOUT")=5 ; Q 1 ; ST1 ;record startup in 870 for single server ;4=status 9=Time Started, 10=Time Stopped, 11=Task Number ;14=Shutdown LLP, 3=LLP Online, 18=Gross Errors N HLJ,X ; HL*1.6*122 remove unnecessary locks ;F L +^HLCS(870,HLDP,0):2 Q:$T S X="HLJ(870,"""_HLDP_","")" S @X@(4)="Init",(@X@(10),@X@(18))="@",@X@(14)=0 I HLTCPCS["C" S @X@(3)=$S(HLTCPLNK["Y":"PC",1:"NC") E S @X@(3)=$S(HLTCPCS["S":"SS",HLTCPCS["M":"MS",1:"") I @X@(3)'="NC" S @X@(9)=$$NOW^XLFDT S:$G(ZTSK) @X@(11)=ZTSK D FILE^HLDIE("","HLJ","","ST1","HLCSTCP") ;HL*1.6*109 ;L -^HLCS(870,HLDP,0) Q ; MON(Y) ;Display current state & check for shutdown ;don't display for multiple server Q:$G(HLLSTN) ; HL*1.6*122 remove unnecessary locks ;F L +^HLCS(870,HLDP,0):2 Q:$T S $P(^HLCS(870,HLDP,0),U,5)=Y ;L -^HLCS(870,HLDP,0) Q:'$D(HLTRACE) N X U IO(0) W !,"IN State: ",Y I '$$STOP D . ; patch HL*1.6*122 . ; R !,"Type Q to Quit: ",X#1:1 . R !,"Type Q to Quit: ",X:1 . ; I $L(X),"Qq"[X S $P(^HLCS(870,HLDP,0),U,15)=1 . I $L(X),"Qq"[$E(X) S $P(^HLCS(870,HLDP,0),U,15)=1 . ; patch HL*1.6*122 end U IO Q UPDT(Y) ;update job count for multiple servers,X=1 increment N HLJ,X ; ; HL*1.6*122 start ; F L +^HLCS(870,HLDP,0):2 Q:$T Q:'$G(HLDP) Q:'$D(^HLCS(870,"E","M",HLDP)) F L +^HLCS(870,HLDP,0):10 Q:$T H 1 ; S X=+$P(^HLCS(870,HLDP,0),U,5),$P(^(0),U,5)=$S(Y:X+1,1:X-1)_" server" S X=+$P(^HLCS(870,HLDP,0),U,5) I X<0 S X=0 S $P(^HLCS(870,HLDP,0),U,5)=$S(Y:(X+1),X<1:0,1:X-1)_" server" ;if incrementing, set the Device Type field to Multi-Server ; I X S HLJ(870,HLDP_",",3)="MS" D FILE^HLDIE("","HLJ","","UPDT","HLCSTCP") I $P(^HLCS(870,HLDP,0),"^",4)']"" S $P(^HLCS(870,HLDP,0),"^",4)="MS" ; HL*1.6*122 end ; L -^HLCS(870,HLDP,0) Q STOP() ;stop flag set N X F L +^HLCS(870,HLDP,0):2 Q:$T S X=+$P(^HLCS(870,HLDP,0),U,15) L -^HLCS(870,HLDP,0) Q X ; LLCNT(DP,Y,Z) ;update Logical Link counters ;DP=ien of Logical Link in file 870 ;Y: 1=msg rec, 2=msg proc, 3=msg to send, 4=msg sent ;Z: ""=add to counter, 1=subtract from counter Q:'$D(^HLCS(870,+$G(DP),0))!('$G(Y)) N P,X S P=$S(Y<3:"IN",1:"OUT")_" QUEUE "_$S(Y#2:"BACK",1:"FRONT")_" POINTER" ; patch HL*1.6*122 start ; F L +^HLCS(870,DP,P):2 Q:$T ; S X=+$G(^HLCS(870,DP,P)),^(P)=X+$S($G(Z):-1,1:1) I '$L($G(OS)) N OS S OS=$G(^%ZOSF("OS")) I OS'["DSM",OS'["OpenM" D . F L +^HLCS(870,DP,P):10 Q:$T H 1 . S X=+$G(^HLCS(870,DP,P)),^(P)=X+$S($G(Z):-1,1:1) . L -^HLCS(870,DP,P) E D . S X=$I(^HLCS(870,DP,P),$S($G(Z):-1,1:1)) ; L -^HLCS(870,DP,P) ; patch HL*1.6*122 end Q SDFLD ; set Shutdown? field to yes Q:'$G(HLDP) ; HL*1.6*122 remove unnecessary lock and call to FM S $P(^HLCS(870,HLDP,0),U,15)=1 ;N HLJ,X ;F L +^HLCS(870,HLDP,0):2 Q:$T ;14=Shutdown LLP? ;S HLJ(870,HLDP_",",14)=1 ;D FILE^HLDIE("","HLJ","","SDFLD","HLCSTCP") ;HL*1.6*109 ;L -^HLCS(870,HLDP,0) Q ; EXITS(Y) ; shutdown and clean up the listener process for either ; single-threaded or multi-threaded N HLJ,X F L +^HLCS(870,HLDP,0):2 Q:$T ;4=status,10=Time Stopped,9=Time Started,11=Task Number S X="HLJ(870,"""_HLDP_","")" S @X@(4)=Y,@X@(11)="@" S:$G(HLCSOUT)'=2 @X@(10)=$$NOW^XLFDT,@X@(9)="@" D FILE^HLDIE("","HLJ","","EXITS","HLCSTCP") ; HL*1.6*109 L -^HLCS(870,HLDP,0) I $D(ZTQUEUED) S ZTREQ="@" ; HL*1.6*122 L -^HLCS("HLTCPLINK",HLDP) Q ; EXITM ;Multiple service shutdown and clean up ; shutdown and clean up a connection spawned by the listener ; process for a multi-threaded listener D UPDT(0) I $D(ZTQUEUED) S ZTREQ="@" Q