- CIANBLIS ;MSC/IND/DKM - MSC RPC Broker ;23-Mar-2011 18:36;PLS
- ;;1.1;CIA NETWORK COMPONENTS;**001007,001008**;Sep 18, 2007
- ;;Copyright 2000-2011, Medsphere Systems Corporation
- ;=================================================================
- ; Start listener process (primary and secondary)
- ; CIAPORT = Listener port
- ; CIAIP = IP address of client
- ; CIAMODE = Connection type:
- ; 0: primary listener - dispatches connections
- ; 1: secondary listener - services individual clients
- ; 2: secondary listener - concurrent mode
- ;
- EN(CIAPORT,CIAIP,CIAMODE) ;PEP - See above
- N CIAVER,CIAOS,CIATDEV,CIAQUIT,CIALN,CIAXUT,CIAUCI,CIARETRY,XWBOS,X,Y,$ET,$ES
- D UCI^%ZOSV
- S U="^",CIAUCI=$P(Y,","),CIAMODE=+$G(CIAMODE),CIAIP=$G(CIAIP),(CIAQUIT,CIARETRY)=0
- D MONSTART^CIANBEVT ; Start background event monitor if not already running
- S:'$G(CIAPORT) CIAPORT=9000 ; Default service port
- Q:'$$STATE(1) ; Quit if listener already running
- S Y=$G(^%ZOSF("OS")),(CIAOS,X)=0
- F XWBOS="DSM","MSM","OpenM" S X=X+1 I Y[XWBOS S CIAOS=X Q
- D:'CIAOS RAISE(15,Y)
- D CLEANUP,STSAVE(0),NULLOPEN,STSAVE(1)
- D:CIAMODE=1 LOGRSRC^%ZOSV("$BROKER HANDLER$",2,1) ; Start RUM for Broker Handler
- D CHPRN("CIA"_$S($L(CIAIP):$P(CIAIP,".",3,4)_":"_CIAPORT,1:CIAPORT)) ; Change process name
- D LISTEN
- D:CIAMODE=1 LOGRSRC^%ZOSV("$BROKER HANDLER$",2,2) ; Stop RUM for handler
- D:CIAQUIT>0!'CIAMODE STATE(0),STREST(1),^%ZISC,STREST(0),CLEANUP,LOGOUT^XUSRB:$G(DUZ)
- I 'CIAMODE,'CIAQUIT J EN^CIANBLIS(CIAPORT) ; Restart primary listener after fatal error
- Q
- ; Entry point for interactive debugging
- DEBUG N CIAPORT,CIAIP
- W !!,"Debug Mode Support",!!
- S CIAIP=$$PMPT("Addr","Enter callback IP address.","127.0.0.1")
- Q:U[CIAIP
- S CIAPORT=$$PMPT("Port","Enter callback port.")
- Q:U[CIAPORT
- I $L($T(^%Serenji)),$$ASK^CIAU("Use Serenji Debugger","Y") D Q
- .N SRJIP,SRJPORT
- .S SRJIP=$$PMPT("Serenji Listener Addr","Enter Serenji listener address",CIAIP)
- .Q:U[SRJIP
- .S SRJPORT=$$PMPT("Serenji Listener Port","Enter Serenji listener port",4321)
- .Q:U[SRJPORT
- .D DEBUG^%Serenji("EN^CIANBLIS(CIAPORT,CIAIP,1)",SRJIP,SRJPORT)
- W !
- D EN(CIAPORT,CIAIP,1)
- Q
- PMPT(PMPT,HELP,DFLT) ;
- N RET
- PMPTX W PMPT,": ",$S($D(DFLT):DFLT_"// ",1:"")
- R RET:$G(DTIME,30)
- E S RET=U
- I $D(DFLT),'$L(RET) S RET=DFLT W DFLT
- W !
- I RET["?" W !,HELP,!! G PMPTX
- Q RET
- ; Entry point for MSERVER process (MSM only)
- MSERVER D EN(%("PORT"),%("ADDRESS"),2)
- Q
- ; Entry point for UCX process (DSM only)
- USERVER D EN($P(%,":",2),$P(%,":"),2)
- Q
- ; Start primary listener
- START(CIAPORT) ;EP
- D SSLIS(,CIAPORT,,1),CLEANUP^CIANBUTL
- Q
- ; Stop primary or secondary listener
- STOP(CIAPORT,CIAIP) ;EP
- D SSLIS(.CIAIP,CIAPORT,,0)
- Q
- ; Start all primary listeners
- STARTALL ;PEP - see above
- D SSALL(1)
- Q
- ; Stop all primary listeners
- STOPALL ;PEP - see above
- D SSALL(0)
- Q
- ; Start/stop all registered listeners
- SSALL(SS,SL) ;
- N IEN,X
- S SL=$G(SL,$D(ZTQUEUED)),U="^"
- F IEN=0:0 S IEN=$O(^CIANB(19941.22,IEN)) Q:'IEN S X=^(IEN,0) D
- .I SS,$P(X,U,3) Q
- .W:'SL !,$P(X,U),": "
- .D SSLIS(,$P(X,U,2),$P(X,U,4),SS,SL)
- Q
- ; Start/stop primary listener
- SSLIS(CIAIP,CIAPORT,CIAUCI,SS,SL) ;
- N CIALN,X,P1,P2,$ET
- S SL=$G(SL,$D(ZTQUEUED))
- S:'SL $ET="D SSERR^CIANBLIS"
- S P1=$S(SS:"start",1:"stop"),P2=P1_$S(SS:"ed",1:"ped")
- I $$STATE=SS W:'SL "Listener ",$S(SS:"already",1:"not")," running on port ",CIAPORT,!! Q
- I 'SS S @$$LOCKNODE=1
- E I $L($G(CIAUCI)) D
- .J EN^CIANBLIS(CIAPORT)[CIAUCI]
- E J EN^CIANBLIS(CIAPORT)
- Q:SL
- W "Waiting for listener to ",P1,"..."
- F X=1:1:5 D
- .H 2
- .W "."
- .S:$$STATE=SS X=99
- I X<99 W "Listener failed to ",P1,!
- E W "Listener ",P2," on port ",CIAPORT,!
- Q
- SSERR W:'$G(SL) "Listener failed to ",P1,": ",$$EC^%ZOSV,!
- S $ET="D UNWIND^%ZTER"
- Q
- ; Main loop
- LISTEN N $ET,$ES
- S $ET="D ETRAP1^CIANBLIS",CIARETRY=0,CIAQUIT='$$TCPOPEN
- F Q:$$QUIT D
- .N $ET,$ES
- .S:$$DOACTION($S(CIAMODE=2&(CIAOS'=3):"C",CIAMODE:"DPQRSU",1:"C")) CIARETRY=0
- D TCPCLOSE
- Q
- ; Read action and params
- ; VAC = List of valid action codes
- ; Returns true if valid inputs
- DOACTION(VAC) ;
- N NM,SB,RT,VL,PR,CIA,ACT,SEQ,ARG,CIAERR,CIADATA,X
- S CIAERR(0)=0
- D TCPUSE
- S X=$$TCPREAD(8,10)
- Q:$E(X,1,5)'="{CIA}" 0
- S ARG=0,CIA("EOD")=$A(X,6),SEQ=$E(X,7),ACT=$E(X,8)
- F S NM=$$TCPREADL Q:'$L(NM) S PR=NM=+NM,RT=$S(PR:"P"_NM,1:"CIA("""_NM_"""") N:PR&'$D(ARG(NM)) @RT D
- .S:PR ARG=$S(NM>ARG:NM,1:ARG),ARG(NM)=""
- .S SB=$$TCPREADL,VL=$$TCPREADL
- .I $L(SB) S RT=RT_$S(PR:"(",1:",")_SB_")"
- .E S:'PR RT=RT_")"
- .S @RT=VL
- W SEQ
- I '$$ERRCHK^CIANBACT(VAC'[ACT,9,ACT) D
- .N $ET,$ES
- .S $ET="D ETRAP2^CIANBLIS"
- .D @("ACT"_ACT_"^CIANBACT")
- I CIAERR(0) D
- .D SNDERR
- E I $D(CIADATA) D
- .D REPLY(.CIADATA)
- E D SNDEOD
- D:'CIAMODE TCPREL
- Q 1
- ; Cleanup environment
- CLEANUP K ^TMP("CIANBRPC",$J),^TMP("CIANBLIS",$J),^XUTL("XQ",$J),@$$LOCKNODE
- Q
- ; Returns true if listener should quit
- QUIT() S:'CIAQUIT CIAQUIT=+$G(@$$LOCKNODE)
- Q CIARETRY>5!CIAQUIT
- ; Save application state
- STSAVE(ST) ;
- D SAVE^XUS1
- K ^TMP("CIANBLIS",$J,ST)
- M ^TMP("CIANBLIS",$J,ST)=^XUTL("XQ",$J)
- Q
- ; Restore application state
- STREST(ST) ;
- K ^XUTL("XQ",$J)
- M ^XUTL("XQ",$J)=^TMP("CIANBLIS",$J,ST)
- K IO
- D RESETVAR^%ZIS
- I ST,$D(IO)#2 D
- .N $ET
- .S $ET="S $EC="""" D NULLOPEN^CIANBLIS"
- .U IO
- Q
- ; Establish null device as default IO device
- NULLOPEN N %ZIS,IOP,POP
- S %ZIS="0H",IOP="NULL"
- D ^%ZIS,RAISE(16):POP
- U IO
- Q
- ; Open TCP listener port
- ; Returns true if successful
- TCPOPEN() ;
- N POP
- S POP=0
- I CIAMODE=2 D
- .S CIATDEV=$S(CIAOS=1:"SYS$NET",CIAOS=2:56,1:$P)
- .I CIAOS=1 O CIATDEV:TCPDEV:5 S POP='$T
- I CIAMODE=1 D
- .D CALL^%ZISTCP(CIAIP,CIAPORT)
- .Q:POP
- .S CIATDEV=IO,IO(0)=IO
- .D:$T(SHARELIC^%ZOSV)'="" SHARELIC^%ZOSV(1)
- I 'CIAMODE D
- .I CIAOS=1 D
- ..S CIATDEV=CIAPORT
- ..O CIATDEV:TCPCHAN:5
- ..S POP='$T
- .I CIAOS=2 S CIATDEV=56
- .I CIAOS=3 D
- ..S CIATDEV="|TCP|"_CIAPORT
- ..O CIATDEV:(:CIAPORT:"DS"):5
- ..S POP='$T
- Q 'POP
- ; Use TCP listener port
- TCPUSE I CIAOS=1 U CIATDEV Q
- I CIAOS=2 D Q
- .I CIAMODE U CIATDEV S:$ZC CIAQUIT=1 Q
- .O CIATDEV
- .U CIATDEV::"TCP"
- .W /SOCKET("",CIAPORT)
- I CIAOS=3 U CIATDEV
- Q
- ; Close TCP listener port
- TCPCLOSE C:$D(CIATDEV) CIATDEV
- Q
- ; Release TCP port
- TCPREL I CIAOS=1 U CIATDEV:DISCONNECT Q
- I CIAOS=2 C CIATDEV Q
- I CIAOS=3 W *-3,*-2
- Q
- ; Read from listener port
- TCPREAD(CNT,TMO) ;
- N X,Y
- S Y="",TMO=$G(TMO,60)
- F Q:CNT'>0 D
- .R X#CNT:TMO
- .I '$L(X) S Y="",CNT=0 S:CIAMODE=2 CIARETRY=CIARETRY+.5
- .E S Y=Y_X,CNT=CNT-$L(X)
- Q Y
- ; Read byte from listener port
- TCPREADB() ;
- Q $A($$TCPREAD(1))
- ; Read length-prefixed data from input stream
- TCPREADL() ;
- N X,L,I,N
- S X=$$TCPREADB
- Q:X=CIA("EOD") ""
- S N=X#16,X=$$TCPREAD(X\16),L=0
- F I=1:1:$L(X) S L=L*256+$A(X,I)
- Q $$TCPREAD(L*16+N)
- ; Raise an exception
- RAISE(MSG,P1,P2) ;
- D GETDLG^CIANBUTL(MSG,.MSG,.P1,.P2)
- S $EC=MSG(1)
- Q
- ; Communication error
- ETRAP1 N ECSAV
- S $ET="D UNWIND^CIANBLIS Q:$Q 0 Q",ECSAV=$EC,CIARETRY=CIARETRY+1
- D:CIARETRY=1&(ECSAV'["READ") ^%ZTER
- S $EC=ECSAV
- Q
- ; Unwind stack
- UNWIND Q:$ES>1
- S $EC=""
- Q
- ; Trapped error, send error info to client
- ETRAP2 N ECSAV
- S $ET="D UNWIND^CIANBLIS Q:$Q 0 Q",ECSAV=$$EC^%ZOSV,CIARETRY=CIARETRY+1
- D:CIARETRY=1 ^%ZTER,ERRCHK^CIANBACT(1,1,ECSAV)
- S $EC=ECSAV
- Q
- ; Send a reply
- REPLY(DATA,ACK) ;
- D TCPUSE
- W $C(+$G(ACK)),$G(DATA)
- D SNDEOD
- Q
- ; Send error information
- SNDERR ;
- N X
- D TCPUSE
- W $C(1)
- D OUT^CIANBACT("CIAERR",1),SNDEOD
- S CIAERR(0)=0
- Q
- ; Send end of data byte if not already sent
- SNDEOD I $D(CIA("EOD")) D
- .D TCPUSE
- .W $C(CIA("EOD")),!
- .K CIA("EOD")
- Q
- ; Lock/Unlock listener
- ; CIAACT: 1 = lock, 0 = unlock, missing = return status
- ; Returns true if locked, false if not.
- STATE(CIAACT) ;
- N RES,Y
- S Y=$$LOCKNODE
- I '$D(CIAACT) D
- .L +@Y:0
- .S RES='$T
- .L:'RES -@Y
- E I CIAACT D
- .L +@Y:1
- .S RES=$T
- E D
- .L -@Y
- .S RES=0
- Q:$Q RES
- Q
- ; Get global reference for lock node
- LOCKNODE(LN) ;
- S:'$D(LN) LN=$NA(^[$G(CIAUCI)]XTMP("CIANBLIS",$G(CIAIP)_":"_CIAPORT_$S($G(CIAMODE)=2:":"_$J,1:"")))
- Q:$Q LN
- Q
- ; Change process name to X
- CHPRN(X) D SETNM^%ZOSV($E(X,1,15))
- Q
- CIANBLIS ;MSC/IND/DKM - MSC RPC Broker ;23-Mar-2011 18:36;PLS
- +1 ;;1.1;CIA NETWORK COMPONENTS;**001007,001008**;Sep 18, 2007
- +2 ;;Copyright 2000-2011, Medsphere Systems Corporation
- +3 ;=================================================================
- +4 ; Start listener process (primary and secondary)
- +5 ; CIAPORT = Listener port
- +6 ; CIAIP = IP address of client
- +7 ; CIAMODE = Connection type:
- +8 ; 0: primary listener - dispatches connections
- +9 ; 1: secondary listener - services individual clients
- +10 ; 2: secondary listener - concurrent mode
- +11 ;
- EN(CIAPORT,CIAIP,CIAMODE) ;PEP - See above
- +1 NEW CIAVER,CIAOS,CIATDEV,CIAQUIT,CIALN,CIAXUT,CIAUCI,CIARETRY,XWBOS,X,Y,$ETRAP,$ESTACK
- +2 DO UCI^%ZOSV
- +3 SET U="^"
- SET CIAUCI=$PIECE(Y,",")
- SET CIAMODE=+$GET(CIAMODE)
- SET CIAIP=$GET(CIAIP)
- SET (CIAQUIT,CIARETRY)=0
- +4 ; Start background event monitor if not already running
- DO MONSTART^CIANBEVT
- +5 ; Default service port
- IF '$GET(CIAPORT)
- SET CIAPORT=9000
- +6 ; Quit if listener already running
- IF '$$STATE(1)
- QUIT
- +7 SET Y=$GET(^%ZOSF("OS"))
- SET (CIAOS,X)=0
- +8 FOR XWBOS="DSM","MSM","OpenM"
- SET X=X+1
- IF Y[XWBOS
- SET CIAOS=X
- QUIT
- +9 IF 'CIAOS
- DO RAISE(15,Y)
- +10 DO CLEANUP
- DO STSAVE(0)
- DO NULLOPEN
- DO STSAVE(1)
- +11 ; Start RUM for Broker Handler
- IF CIAMODE=1
- DO LOGRSRC^%ZOSV("$BROKER HANDLER$",2,1)
- +12 ; Change process name
- DO CHPRN("CIA"_$SELECT($LENGTH(CIAIP):$PIECE(CIAIP,".",3,4)_":"_CIAPORT,1:CIAPORT))
- +13 DO LISTEN
- +14 ; Stop RUM for handler
- IF CIAMODE=1
- DO LOGRSRC^%ZOSV("$BROKER HANDLER$",2,2)
- +15 IF CIAQUIT>0!'CIAMODE
- DO STATE(0)
- DO STREST(1)
- DO ^%ZISC
- DO STREST(0)
- DO CLEANUP
- IF $GET(DUZ)
- DO LOGOUT^XUSRB
- +16 ; Restart primary listener after fatal error
- IF 'CIAMODE
- IF 'CIAQUIT
- JOB EN^CIANBLIS(CIAPORT)
- +17 QUIT
- +18 ; Entry point for interactive debugging
- DEBUG NEW CIAPORT,CIAIP
- +1 WRITE !!,"Debug Mode Support",!!
- +2 SET CIAIP=$$PMPT("Addr","Enter callback IP address.","127.0.0.1")
- +3 IF U[CIAIP
- QUIT
- +4 SET CIAPORT=$$PMPT("Port","Enter callback port.")
- +5 IF U[CIAPORT
- QUIT
- +6 IF $LENGTH($TEXT(^%Serenji))
- IF $$ASK^CIAU("Use Serenji Debugger","Y")
- Begin DoDot:1
- +7 NEW SRJIP,SRJPORT
- +8 SET SRJIP=$$PMPT("Serenji Listener Addr","Enter Serenji listener address",CIAIP)
- +9 IF U[SRJIP
- QUIT
- +10 SET SRJPORT=$$PMPT("Serenji Listener Port","Enter Serenji listener port",4321)
- +11 IF U[SRJPORT
- QUIT
- +12 DO DEBUG^%Serenji("EN^CIANBLIS(CIAPORT,CIAIP,1)",SRJIP,SRJPORT)
- End DoDot:1
- QUIT
- +13 WRITE !
- +14 DO EN(CIAPORT,CIAIP,1)
- +15 QUIT
- PMPT(PMPT,HELP,DFLT) ;
- +1 NEW RET
- PMPTX WRITE PMPT,": ",$SELECT($DATA(DFLT):DFLT_"// ",1:"")
- +1 READ RET:$GET(DTIME,30)
- +2 IF '$TEST
- SET RET=U
- +3 IF $DATA(DFLT)
- IF '$LENGTH(RET)
- SET RET=DFLT
- WRITE DFLT
- +4 WRITE !
- +5 IF RET["?"
- WRITE !,HELP,!!
- GOTO PMPTX
- +6 QUIT RET
- +7 ; Entry point for MSERVER process (MSM only)
- MSERVER DO EN(%("PORT"),%("ADDRESS"),2)
- +1 QUIT
- +2 ; Entry point for UCX process (DSM only)
- USERVER DO EN($PIECE(%,":",2),$PIECE(%,":"),2)
- +1 QUIT
- +2 ; Start primary listener
- START(CIAPORT) ;EP
- +1 DO SSLIS(,CIAPORT,,1)
- DO CLEANUP^CIANBUTL
- +2 QUIT
- +3 ; Stop primary or secondary listener
- STOP(CIAPORT,CIAIP) ;EP
- +1 DO SSLIS(.CIAIP,CIAPORT,,0)
- +2 QUIT
- +3 ; Start all primary listeners
- STARTALL ;PEP - see above
- +1 DO SSALL(1)
- +2 QUIT
- +3 ; Stop all primary listeners
- STOPALL ;PEP - see above
- +1 DO SSALL(0)
- +2 QUIT
- +3 ; Start/stop all registered listeners
- SSALL(SS,SL) ;
- +1 NEW IEN,X
- +2 SET SL=$GET(SL,$DATA(ZTQUEUED))
- SET U="^"
- +3 FOR IEN=0:0
- SET IEN=$ORDER(^CIANB(19941.22,IEN))
- IF 'IEN
- QUIT
- SET X=^(IEN,0)
- Begin DoDot:1
- +4 IF SS
- IF $PIECE(X,U,3)
- QUIT
- +5 IF 'SL
- WRITE !,$PIECE(X,U),": "
- +6 DO SSLIS(,$PIECE(X,U,2),$PIECE(X,U,4),SS,SL)
- End DoDot:1
- +7 QUIT
- +8 ; Start/stop primary listener
- SSLIS(CIAIP,CIAPORT,CIAUCI,SS,SL) ;
- +1 NEW CIALN,X,P1,P2,$ETRAP
- +2 SET SL=$GET(SL,$DATA(ZTQUEUED))
- +3 IF 'SL
- SET $ETRAP="D SSERR^CIANBLIS"
- +4 SET P1=$SELECT(SS:"start",1:"stop")
- SET P2=P1_$SELECT(SS:"ed",1:"ped")
- +5 IF $$STATE=SS
- IF 'SL
- WRITE "Listener ",$SELECT(SS:"already",1:"not")," running on port ",CIAPORT,!!
- QUIT
- +6 IF 'SS
- SET @$$LOCKNODE=1
- +7 IF '$TEST
- IF $LENGTH($GET(CIAUCI))
- Begin DoDot:1
- +8 JOB EN^CIANBLIS(CIAPORT)[CIAUCI]
- End DoDot:1
- +9 IF '$TEST
- JOB EN^CIANBLIS(CIAPORT)
- +10 IF SL
- QUIT
- +11 WRITE "Waiting for listener to ",P1,"..."
- +12 FOR X=1:1:5
- Begin DoDot:1
- +13 HANG 2
- +14 WRITE "."
- +15 IF $$STATE=SS
- SET X=99
- End DoDot:1
- +16 IF X<99
- WRITE "Listener failed to ",P1,!
- +17 IF '$TEST
- WRITE "Listener ",P2," on port ",CIAPORT,!
- +18 QUIT
- SSERR IF '$GET(SL)
- WRITE "Listener failed to ",P1,": ",$$EC^%ZOSV,!
- +1 SET $ETRAP="D UNWIND^%ZTER"
- +2 QUIT
- +3 ; Main loop
- LISTEN NEW $ETRAP,$ESTACK
- +1 SET $ETRAP="D ETRAP1^CIANBLIS"
- SET CIARETRY=0
- SET CIAQUIT='$$TCPOPEN
- +2 FOR
- IF $$QUIT
- QUIT
- Begin DoDot:1
- +3 NEW $ETRAP,$ESTACK
- +4 IF $$DOACTION($SELECT(CIAMODE=2&(CIAOS'=3)
- SET CIARETRY=0
- End DoDot:1
- +5 DO TCPCLOSE
- +6 QUIT
- +7 ; Read action and params
- +8 ; VAC = List of valid action codes
- +9 ; Returns true if valid inputs
- DOACTION(VAC) ;
- +1 NEW NM,SB,RT,VL,PR,CIA,ACT,SEQ,ARG,CIAERR,CIADATA,X
- +2 SET CIAERR(0)=0
- +3 DO TCPUSE
- +4 SET X=$$TCPREAD(8,10)
- +5 IF $EXTRACT(X,1,5)'="{CIA}"
- QUIT 0
- +6 SET ARG=0
- SET CIA("EOD")=$ASCII(X,6)
- SET SEQ=$EXTRACT(X,7)
- SET ACT=$EXTRACT(X,8)
- +7 FOR
- SET NM=$$TCPREADL
- IF '$LENGTH(NM)
- QUIT
- SET PR=NM=+NM
- SET RT=$SELECT(PR:"P"_NM,1:"CIA("""_NM_"""")
- IF PR&'$DATA(ARG(NM))
- NEW @RT
- Begin DoDot:1
- +8 IF PR
- SET ARG=$SELECT(NM>ARG:NM,1:ARG)
- SET ARG(NM)=""
- +9 SET SB=$$TCPREADL
- SET VL=$$TCPREADL
- +10 IF $LENGTH(SB)
- SET RT=RT_$SELECT(PR:"(",1:",")_SB_")"
- +11 IF '$TEST
- IF 'PR
- SET RT=RT_")"
- +12 SET @RT=VL
- End DoDot:1
- +13 WRITE SEQ
- +14 IF '$$ERRCHK^CIANBACT(VAC'[ACT,9,ACT)
- Begin DoDot:1
- +15 NEW $ETRAP,$ESTACK
- +16 SET $ETRAP="D ETRAP2^CIANBLIS"
- +17 DO @("ACT"_ACT_"^CIANBACT")
- End DoDot:1
- +18 IF CIAERR(0)
- Begin DoDot:1
- +19 DO SNDERR
- End DoDot:1
- +20 IF '$TEST
- IF $DATA(CIADATA)
- Begin DoDot:1
- +21 DO REPLY(.CIADATA)
- End DoDot:1
- +22 IF '$TEST
- DO SNDEOD
- +23 IF 'CIAMODE
- DO TCPREL
- +24 QUIT 1
- +25 ; Cleanup environment
- CLEANUP KILL ^TMP("CIANBRPC",$JOB),^TMP("CIANBLIS",$JOB),^XUTL("XQ",$JOB),@$$LOCKNODE
- +1 QUIT
- +2 ; Returns true if listener should quit
- QUIT() IF 'CIAQUIT
- SET CIAQUIT=+$GET(@$$LOCKNODE)
- +1 QUIT CIARETRY>5!CIAQUIT
- +2 ; Save application state
- STSAVE(ST) ;
- +1 DO SAVE^XUS1
- +2 KILL ^TMP("CIANBLIS",$JOB,ST)
- +3 MERGE ^TMP("CIANBLIS",$JOB,ST)=^XUTL("XQ",$JOB)
- +4 QUIT
- +5 ; Restore application state
- STREST(ST) ;
- +1 KILL ^XUTL("XQ",$JOB)
- +2 MERGE ^XUTL("XQ",$JOB)=^TMP("CIANBLIS",$JOB,ST)
- +3 KILL IO
- +4 DO RESETVAR^%ZIS
- +5 IF ST
- IF $DATA(IO)#2
- Begin DoDot:1
- +6 NEW $ETRAP
- +7 SET $ETRAP="S $EC="""" D NULLOPEN^CIANBLIS"
- +8 USE IO
- End DoDot:1
- +9 QUIT
- +10 ; Establish null device as default IO device
- NULLOPEN NEW %ZIS,IOP,POP
- +1 SET %ZIS="0H"
- SET IOP="NULL"
- +2 DO ^%ZIS
- IF POP
- DO RAISE(16)
- +3 USE IO
- +4 QUIT
- +5 ; Open TCP listener port
- +6 ; Returns true if successful
- TCPOPEN() ;
- +1 NEW POP
- +2 SET POP=0
- +3 IF CIAMODE=2
- Begin DoDot:1
- +4 SET CIATDEV=$SELECT(CIAOS=1:"SYS$NET",CIAOS=2:56,1:$PRINCIPAL)
- +5 IF CIAOS=1
- OPEN CIATDEV:TCPDEV:5
- SET POP='$TEST
- End DoDot:1
- +6 IF CIAMODE=1
- Begin DoDot:1
- +7 DO CALL^%ZISTCP(CIAIP,CIAPORT)
- +8 IF POP
- QUIT
- +9 SET CIATDEV=IO
- SET IO(0)=IO
- +10 IF $TEXT(SHARELIC^%ZOSV)'=""
- DO SHARELIC^%ZOSV(1)
- End DoDot:1
- +11 IF 'CIAMODE
- Begin DoDot:1
- +12 IF CIAOS=1
- Begin DoDot:2
- +13 SET CIATDEV=CIAPORT
- +14 OPEN CIATDEV:TCPCHAN:5
- +15 SET POP='$TEST
- End DoDot:2
- +16 IF CIAOS=2
- SET CIATDEV=56
- +17 IF CIAOS=3
- Begin DoDot:2
- +18 SET CIATDEV="|TCP|"_CIAPORT
- +19 OPEN CIATDEV:(:CIAPORT:"DS"):5
- +20 SET POP='$TEST
- End DoDot:2
- End DoDot:1
- +21 QUIT 'POP
- +22 ; Use TCP listener port
- TCPUSE IF CIAOS=1
- USE CIATDEV
- QUIT
- +1 IF CIAOS=2
- Begin DoDot:1
- +2 IF CIAMODE
- USE CIATDEV
- IF $ZC
- SET CIAQUIT=1
- QUIT
- +3 OPEN CIATDEV
- +4 USE CIATDEV::"TCP"
- +5 WRITE /SOCKET("",CIAPORT)
- End DoDot:1
- QUIT
- +6 IF CIAOS=3
- USE CIATDEV
- +7 QUIT
- +8 ; Close TCP listener port
- TCPCLOSE IF $DATA(CIATDEV)
- CLOSE CIATDEV
- +1 QUIT
- +2 ; Release TCP port
- TCPREL IF CIAOS=1
- USE CIATDEV:DISCONNECT
- QUIT
- +1 IF CIAOS=2
- CLOSE CIATDEV
- QUIT
- +2 IF CIAOS=3
- WRITE *-3,*-2
- +3 QUIT
- +4 ; Read from listener port
- TCPREAD(CNT,TMO) ;
- +1 NEW X,Y
- +2 SET Y=""
- SET TMO=$GET(TMO,60)
- +3 FOR
- IF CNT'>0
- QUIT
- Begin DoDot:1
- +4 READ X#CNT:TMO
- +5 IF '$LENGTH(X)
- SET Y=""
- SET CNT=0
- IF CIAMODE=2
- SET CIARETRY=CIARETRY+.5
- +6 IF '$TEST
- SET Y=Y_X
- SET CNT=CNT-$LENGTH(X)
- End DoDot:1
- +7 QUIT Y
- +8 ; Read byte from listener port
- TCPREADB() ;
- +1 QUIT $ASCII($$TCPREAD(1))
- +2 ; Read length-prefixed data from input stream
- TCPREADL() ;
- +1 NEW X,L,I,N
- +2 SET X=$$TCPREADB
- +3 IF X=CIA("EOD")
- QUIT ""
- +4 SET N=X#16
- SET X=$$TCPREAD(X\16)
- SET L=0
- +5 FOR I=1:1:$LENGTH(X)
- SET L=L*256+$ASCII(X,I)
- +6 QUIT $$TCPREAD(L*16+N)
- +7 ; Raise an exception
- RAISE(MSG,P1,P2) ;
- +1 DO GETDLG^CIANBUTL(MSG,.MSG,.P1,.P2)
- +2 SET $ECODE=MSG(1)
- +3 QUIT
- +4 ; Communication error
- ETRAP1 NEW ECSAV
- +1 SET $ETRAP="D UNWIND^CIANBLIS Q:$Q 0 Q"
- SET ECSAV=$ECODE
- SET CIARETRY=CIARETRY+1
- +2 IF CIARETRY=1&(ECSAV'["READ")
- DO ^%ZTER
- +3 SET $ECODE=ECSAV
- +4 QUIT
- +5 ; Unwind stack
- UNWIND IF $ESTACK>1
- QUIT
- +1 SET $ECODE=""
- +2 QUIT
- +3 ; Trapped error, send error info to client
- ETRAP2 NEW ECSAV
- +1 SET $ETRAP="D UNWIND^CIANBLIS Q:$Q 0 Q"
- SET ECSAV=$$EC^%ZOSV
- SET CIARETRY=CIARETRY+1
- +2 IF CIARETRY=1
- DO ^%ZTER
- DO ERRCHK^CIANBACT(1,1,ECSAV)
- +3 SET $ECODE=ECSAV
- +4 QUIT
- +5 ; Send a reply
- REPLY(DATA,ACK) ;
- +1 DO TCPUSE
- +2 WRITE $CHAR(+$GET(ACK)),$GET(DATA)
- +3 DO SNDEOD
- +4 QUIT
- +5 ; Send error information
- SNDERR ;
- +1 NEW X
- +2 DO TCPUSE
- +3 WRITE $CHAR(1)
- +4 DO OUT^CIANBACT("CIAERR",1)
- DO SNDEOD
- +5 SET CIAERR(0)=0
- +6 QUIT
- +7 ; Send end of data byte if not already sent
- SNDEOD IF $DATA(CIA("EOD"))
- Begin DoDot:1
- +1 DO TCPUSE
- +2 WRITE $CHAR(CIA("EOD")),!
- +3 KILL CIA("EOD")
- End DoDot:1
- +4 QUIT
- +5 ; Lock/Unlock listener
- +6 ; CIAACT: 1 = lock, 0 = unlock, missing = return status
- +7 ; Returns true if locked, false if not.
- STATE(CIAACT) ;
- +1 NEW RES,Y
- +2 SET Y=$$LOCKNODE
- +3 IF '$DATA(CIAACT)
- Begin DoDot:1
- +4 LOCK +@Y:0
- +5 SET RES='$TEST
- +6 IF 'RES
- LOCK -@Y
- End DoDot:1
- +7 IF '$TEST
- IF CIAACT
- Begin DoDot:1
- +8 LOCK +@Y:1
- +9 SET RES=$TEST
- End DoDot:1
- +10 IF '$TEST
- Begin DoDot:1
- +11 LOCK -@Y
- +12 SET RES=0
- End DoDot:1
- +13 IF $QUIT
- QUIT RES
- +14 QUIT
- +15 ; Get global reference for lock node
- LOCKNODE(LN) ;
- +1 IF '$DATA(LN)
- SET LN=$NAME(^[$GET(CIAUCI)]XTMP("CIANBLIS",$GET(CIAIP)_":"_CIAPORT_$SELECT($GET(CIAMODE)=2:":"_$JOB,1:"")))
- +2 IF $QUIT
- QUIT LN
- +3 QUIT
- +4 ; Change process name to X
- CHPRN(X) DO SETNM^%ZOSV($EXTRACT(X,1,15))
- +1 QUIT