Home   Package List   Routine Alphabetical List   Global Alphabetical List   FileMan Files List   FileMan Sub-Files List   Package Component Lists   Package-Namespace Mapping  
Routine: INHVTMT

INHVTMT.m

Go to the documentation of this file.
  1. INHVTMT ; DGH, CHEM, KAC ; 02 Nov 1999 17:52 ; Multi-threaded socket transceiver
  1. ;;3.01;BHL IHS Interfaces with GIS;;JUL 01, 2001
  1. ;COPYRIGHT 1991-2000 SAIC
  1. Q
  1. ;
  1. EN N INA,INDA,INDEST,INDSTR,INUSEQ,INSEND,INSND,INERR,INUIF,INLOOP,OUT,RCVE,OK,UIF,X,ER,INCHNL,INIP,INMEM,INQPRI,INQTIME,INNORSP,SYSTEM,RUN,MSG,CLISRV,INBPNM,INMSASTA,INSTOP
  1. N H,INDISCNT,INDISCON,INDONE,INDT,INERRMT,INHBSENT,INHBTRY,INHBWAIT,INITROU,INIVLEN,INLIN,INLOGMSG,INMLTHRD,INMSG,INNORESP,INPEND,INRECV,INRECVD,INRUNMT,INSENT,INSEQNUM,INSTATE,INSTD,INSYNC,INTM,INTMDUE,INTMSENT,INXDST,RC
  1. S INSTD="PDTS" ; set via FFCR in future - flags project-specific coding
  1. S X="ERR^INHVTMT5",@^%ZOSF("TRAP")
  1. S SYSTEM="SC",INBPNM=$P($G(^INTHPC(INBPN,0)),U),INSTATE="OPEN",INMLTHRD=1,INHBTRY=20,(INHBSENT,INDISCNT)=0,INIVLEN=12
  1. D DEBUG^INHVCRA1() ; turn on debug
  1. ;Start GIS Background process audit if flag is set in Site Parms File
  1. D AUDCHK^XUSAUD D:$D(XUAUDIT) ITIME^XUSAUD(INBPNM)
  1. D:'$$RUN^INHOTM ; ck shutdown status
  1. . D:$G(INDEBUG) LOG^INHVCRA1("Shutdown transceiver "_INBPNM,"E")
  1. . D SHUTDWN^INHVTMT5(INBPN)
  1. L +^INRHB("RUN",INBPN):5 E D Q
  1. . D:$G(INDEBUG) LOG^INHVCRA1("Cannot get exclusive lock for: ^INRHB(""RUN"","_INBPN_")","E")
  1. . D SHUTDWN^INHVTMT5(INBPN)
  1. ; Get INTERFACE DESTINATION IEN & Destination Determination Code
  1. S INDSTR=+$P(^INTHPC(INBPN,0),U,7),INXDST=$G(^(8))
  1. I 'INDSTR D Q
  1. . D:$G(INDEBUG) LOG^INHVCRA1("No destination designated for background process "_INBPNM,"E")
  1. . D SHUTDWN^INHVTMT5(INBPN)
  1. I '$L($G(INXDST)) D Q
  1. . D:$G(INDEBUG) LOG^INHVCRA1("Missing code to determine inbound message destination for background process "_INBPNM,"E")
  1. . D SHUTDWN^INHVTMT5(INBPN)
  1. ; Initialize variables from background process file
  1. D:$G(INDEBUG) LOG^INHVCRA1("Initializing variables for background process file "_INBPNM,9)
  1. D INIT^INHUVUT(INBPN,.INIP) ; get parms from BPC file
  1. I $L($G(INSTD)) D ; project-specific init
  1. . F X=1:1:9 S INITROU="INIT"_INSTD_"^INHVTMT"_X D:$L($T(@INITROU)) @INITROU
  1. ; if Encryption is flagged on, start C process
  1. I $G(INIP("CRYPT")),'$L(INIP("DESKEY")) D Q
  1. . D:$G(INDEBUG) LOG^INHVCRA1("Encrypt is set but no DES Key specified "_INBPNM,5)
  1. . D SHUTDWN^INHVTMT5(INBPN)
  1. I $G(INIP("CRYPT")) S X=$$CRYPON^INCRYPT(INIP("DESKEY"))
  1. ;Determine if process will be client (default,0) or server (1)
  1. S CLISRV=+$P(^INTHPC(INBPN,0),U,8)
  1. ; sync up INPEND with current state of pend que
  1. S INSYNC=$$PENDSYNC^INHVTMT4(.INPEND)
  1. ;
  1. ; Main program loop
  1. F D Q:'$G(INRUNMT)
  1. .; Update background process audit
  1. . D:$D(XUAUDIT) ITIME^XUSAUD(INBPNM)
  1. .;
  1. .; Select port & open TCP/IP connection
  1. . I INSTATE="OPEN" D Q:'INRUNMT
  1. .. D CLOSE^INHVTMT5
  1. .. D:$G(INDEBUG) LOG^INHVCRA1("OPEN: Transceiver "_INBPNM,1)
  1. .. S INRUNMT=$$OPEN^INHVTAPU(INBPN,CLISRV,.INIP,INDEBUG,.INCHNL,.INMEM)
  1. .. S:INRUNMT INSTATE="HB",INHBWAIT=0
  1. .;
  1. .; Heartbeat/dummy msg sent to target system for known, pervasive
  1. .; problems til target sends msg indicating that msgs can flow again
  1. . I INSTATE="HB" D Q:'INRUNMT
  1. .. Q:'$L($G(INIP("INIT"))) ; hb not used (e.g. receipt ack precludes)
  1. .. D:$G(INDEBUG) LOG^INHVCRA1("HB: Transceiver "_INBPNM,1)
  1. .. I (INHBTRY'>INHBSENT) S INSTATE="OPEN",INHBSENT=0 Q ; close/reopen
  1. .. S INRUNMT=$$HB^INHVTMT5(.INHBSENT,INHBWAIT) ; send heartbeat msg
  1. .. S:INRUNMT INHBWAIT=1
  1. .;
  1. . I INSTATE="SEND" D Q:'INRUNMT S:INSTATE="SEND" INSTATE="RECV"
  1. .. D:$G(INDEBUG) LOG^INHVCRA1("SEND: Transceiver "_INBPNM,1)
  1. .. S INSEND=INIP("SMAX")-INPEND ; # msgs to send
  1. .. S INSENT=0 ; # msgs sent
  1. ..; Send up to max transactions
  1. .. F Q:(INSEND'>INSENT) D Q:(INSTATE'="SEND")!'INRUNMT
  1. ...; Get next transaction from destination queue
  1. ... S INUIF=""
  1. ... F D Q:INUIF!(INSTATE'="SEND")!'INRUNMT
  1. .... D:$G(INDEBUG) LOG^INHVCRA1("Socket ready to start send/receive.",7)
  1. .... S INRUNMT=$$INRHB^INHUVUT1(INBPN,"Idle") Q:'INRUNMT
  1. .... D:$G(INDEBUG) LOG^INHVCRA1("Getting next transaction on "_INDSTR_" destination queue.",7)
  1. .... S INUIF=$$NEXT^INHUVUT3(INDSTR,.INQPRI,.INQTIME,.INPEND)
  1. .... I 'INUIF D Q
  1. ..... S INSTATE="RECV" ; nothing to send
  1. ..... D:$G(INDEBUG) LOG^INHVCRA1("No transactions on destination queue.",5)
  1. ...;
  1. ... Q:(INSTATE'="SEND")!'INRUNMT
  1. ...;
  1. ...; Ck for presence of msg content
  1. ... D:$G(INDEBUG) LOG^INHVCRA1("Checking for presence of message",7)
  1. ... I '$O(^INTHU(INUIF,3,0)) D Q
  1. .... D ENR^INHE(INBPN,"Missing message "_INUIF_" for destination "_$P($G(^INRHD(INDSTR,0)),U))
  1. .... D PQKILL^INHVTMT4(INDSTR,INSEQNUM,INUIF,.INPEND)
  1. ...;
  1. ...; Selective Routing (send/no send)
  1. ... S UIF=$G(^INTHU(INUIF,0)),INA="^INTHU("_INUIF_",7)",INDA="^INTHU("_INUIF_",6)"
  1. ... I $$SUPPRESS^INHUT6("XMT",$P(UIF,U,11),$P(UIF,U,2),INBPN,.INA,.INDA,INUIF) D Q
  1. .... D PQKILL^INHVTMT4(INDSTR,INSEQNUM,INUIF,.INPEND)
  1. ...;
  1. ...; Send msg
  1. ...; Start transaction audit
  1. ... D:$D(XUAUDIT) TTSTRT^XUSAUD(INUIF,"",INBPNM,"","TRANSMIT")
  1. ... D:$G(INDEBUG) LOG^INHVCRA1("Sending outgoing message on "_INBPNM,7)
  1. ... S INRUNMT=$$INRHB^INHUVUT1(INBPN,"Sending UIF= "_INUIF) Q:'INRUNMT
  1. ... F S INERRMT=$$SEND^INHVTMT1(INUIF,INCHNL,.INIP) Q:'INERRMT!'INRUNMT
  1. ...; Post-send activities
  1. ... D ULOG^INHU(INUIF,"S") ; log activity in UIF - sent
  1. ... S INSENT=INSENT+1
  1. ... S $P(^INLHDEST(INDSTR,"PEND",INBPN,INSEQNUM,INUIF),U)=$H_U_1
  1. ... D:$D(XUAUDIT) TTSTP^XUSAUD(0) ;stop transaction audit
  1. .;
  1. . I "^RECV^HB^"[(U_INSTATE_U) D Q:'INRUNMT S:INSTATE="RECV" INSTATE="TIMEOUT"
  1. .. D:$G(INDEBUG) LOG^INHVCRA1("RECV: Transceiver "_INBPNM,1)
  1. .. S (INRECV,INDONE,INDISCON,INNORESP)=0
  1. ..; Receive til disconnect, no response after retries, stop transceiver
  1. ..; or done reading (e.g. INPEND=0)
  1. .. F D Q:INDONE!INDISCON!INNORESP!'INRUNMT
  1. ... S INMSG="Waiting for response"
  1. ... D:$G(INDEBUG) LOG^INHVCRA1(INMSG_" on "_INBPNM,7)
  1. ... S INRUNMT=$$INRHB^INHUVUT1(INBPN,INMSG) Q:'INRUNMT
  1. ... S INERRMT=$$RECEIVE^INHVTMT2(.INCHNL,.INIP,.INERR,.INMEM)
  1. ... Q:'INRUNMT
  1. ... S INDISCON=(INERRMT=3),INDONE=(INERRMT=0)
  1. ...;
  1. ... I INDISCON D Q ; disconnect
  1. .... D REROUTE^INHVTMT4(INDSTR,.INPEND)
  1. .... S INSTATE="OPEN"
  1. .... D ENR^INHE(INBPN,INERR)
  1. .... D:$G(INDEBUG) LOG^INHVCRA1(INERR,5) K INERR
  1. .... D:'CLISRV
  1. .....; clients pause before close/reopen; srvrs expect disconnects
  1. ..... S INLOGMSG="Waiting "_INIP("DHNG")_" seconds for open retry following disconnect on "_INBPNM_". Attempt "_INDISCNT
  1. ..... D:$G(INDEBUG) LOG^INHVCRA1(INLOGMSG,7)
  1. ..... D WAIT^INHUVUT2(INBPN,INIP("DHNG"),INLOGMSG,.INRUNMT)
  1. ..... S INRUNMT='INRUNMT ; wait rtns opposite
  1. ...;
  1. ... Q:INDONE ; finished reading available data
  1. ...;
  1. ...; No response (1) or error (2), try reading up to read-try max
  1. ... D:$G(INDEBUG) LOG^INHVCRA1(INERR,5) K INERR
  1. ... S INRECV=INRECV+1,INNORESP=$S(INIP("RTRY")'>INRECV:1,1:0)
  1. ...; If read retries exceeded
  1. ... I INNORESP D Q ; max read tries exceeded - no response (1) or error (2)
  1. .... D:$G(INDEBUG) LOG^INHVCRA1("Maximum receive retries,"_INIP("RTRY")_" exceeded.",7)
  1. ...; Read retry - max retries NOT exceeded
  1. ... D:$G(INDEBUG) LOG^INHVCRA1("Waiting "_INIP("RHNG")_" seconds for read retry.",7)
  1. ... H INIP("RHNG")
  1. .;
  1. .; Ck all entries on "pending response" que for no-response timeout
  1. . I "^TIMEOUT^HB^"[(U_INSTATE_U) D Q:'INRUNMT S:INSTATE="TIMEOUT" INSTATE="SEND"
  1. .. D:$G(INDEBUG) LOG^INHVCRA1("TIMEOUT: Transceiver "_INBPNM,1)
  1. .. S:INSYNC INSYNC=0 ; ensured FIFO on startup (TIMEOUT before SEND state)
  1. ..; Quit if no items in pending queue
  1. .. I '$D(^INLHDEST(INDSTR,"PEND",INBPN)) S INPEND=0 Q
  1. .. S INRUNMT=$$INRHB^INHUVUT1(INBPN,"Cking for no-response timeout") Q:'INRUNMT
  1. .. S INSEQNUM=""
  1. .. F S INSEQNUM=$O(^INLHDEST(INDSTR,"PEND",INBPN,INSEQNUM)) Q:(INSEQNUM="") D Q:'INRUNMT
  1. ... S INUIF=""
  1. ... F S INUIF=$O(^INLHDEST(INDSTR,"PEND",INBPN,INSEQNUM,INUIF)) Q:'INUIF D Q:'INRUNMT
  1. .... S INTMSENT=$P(^INLHDEST(INDSTR,"PEND",INBPN,INSEQNUM,INUIF),U)
  1. .... S X=$P(INTMSENT,",",2)+INIP("STO")
  1. ....; ck for crossing day boundary
  1. .... S INTMDUE=$S(86400'>X:($P(INTMSENT,",")+1)_","_$TR($J(X-86400,5)," ",0),1:$P(INTMSENT,",")_","_X)
  1. .... S H=$H,INDT=$P(H,","),INTM=$P(H,",",2)
  1. ....; If past due date or today's date, but past due time
  1. .... I ($P(INTMDUE,",")<INDT)!(($P(INTMDUE,",")=INDT)&($P(INTMDUE,",",2)'>INTM)) D
  1. .....; If no-response timeout
  1. ..... I INIP("STRY")'>$P(^INLHDEST(INDSTR,"PEND",INBPN,INSEQNUM,INUIF),U,2) D Q
  1. ......; send tries exceeded, reroute msg to another xceiver
  1. ...... S INERR="No-response timeout: Rerouting UIF="_INUIF_" for background process "_INBPNM_$S(INSTATE="TIMEOUT":". Close/reopen socket. Transceiver entering heartbeat state.",1:"")
  1. ...... D:$G(INDEBUG) LOG^INHVCRA1(INERR,9)
  1. ...... D ENR^INHE(INBPN,INERR) K INERR
  1. ...... S INERRMT=$$GETPEND^INHVTMT4(INDSTR,INSEQNUM,INUIF,.INPEND)
  1. ...... S INSTATE="OPEN"
  1. .....; else, send retries NOT exceeded
  1. ..... D:$G(INDEBUG) LOG^INHVCRA1("No-response timeout: Resending UIF="_INUIF,9)
  1. ..... D RESEND^INHVTMT4(INDSTR,INUIF,INSEQNUM)
  1. ;
  1. ;
  1. ; Shutdown transceiver (close socket, cleanup)
  1. D SHUTDWN^INHVTMT5(INBPN,$G(INCHNL))
  1. Q
  1. ;
  1. ;