| 1 | XWBTCPL ;SLC/KCM - Listener for TCP connects ;12/09/2004  07:33 | 
|---|
| 2 | ;;1.1;RPC BROKER;**1,7,9,15,16,35**;Mar 28, 1997 | 
|---|
| 3 | ;ISC-SF/EG - DHCP Broker | 
|---|
| 4 | ; | 
|---|
| 5 | ; This routine is the background process that listens for client | 
|---|
| 6 | ; requests to connect to M.  When a request is received, This | 
|---|
| 7 | ; procedure will job a routine to handle the requests of the client. | 
|---|
| 8 | ; | 
|---|
| 9 | ; This job may be started in the background with:  D STRT^XWBTCP(PORT) | 
|---|
| 10 | ; | 
|---|
| 11 | ; When running, this job may be stopped with:      D STOP^XWBTCP(PORT) | 
|---|
| 12 | ; | 
|---|
| 13 | ; Where port is the known service port to listen for connections | 
|---|
| 14 | ; p*35 Moved reads and writes to XWBRW | 
|---|
| 15 | ; | 
|---|
| 16 | EN(XWBTSKT) ; -- accept clients and start the individual message handler | 
|---|
| 17 | N $ETRAP,$ESTACK S $ETRAP="D ^%ZTER J EN^XWBTCPL($G(XWBTSKT)) HALT" | 
|---|
| 18 | N RETRY,X,XWBVER,XWBVOL,LEN,MSG,XWBOS,DONE,DSMTCP,NATIP,XWBRBUF | 
|---|
| 19 | N XWBTIME | 
|---|
| 20 | S U="^",RETRY="START" | 
|---|
| 21 | X ^%ZOSF("UCI") S XWBVOL=$P(Y,",",2) ;(*p7,p9*) | 
|---|
| 22 | IF $G(XWBTSKT)="" S XWBTSKT=9000 ; default service port | 
|---|
| 23 | S XWBTDEV=XWBTSKT | 
|---|
| 24 | ; | 
|---|
| 25 | Q:'$$SEMAPHOR(XWBTSKT,"LOCK")  ; -- quit if job is already running | 
|---|
| 26 | ; | 
|---|
| 27 | S XWBDEBUG=$$GET^XPAR("SYS","XWBDEBUG") ;(*p35) | 
|---|
| 28 | I XWBDEBUG D LOGSTART^XWBDLOG("XWBTCPL") ;(*p35) | 
|---|
| 29 | D UPDTREC(XWBTSKT,3) ;updt RPC BROKER SITE PARAMETER record as RUNNING | 
|---|
| 30 | D MARKER^XWBTCP(XWBTSKT,-1) ;Clear marker | 
|---|
| 31 | ; | 
|---|
| 32 | D SETNM^%ZOSV($E("RPCB_Port:"_XWBTSKT,1,15)) ;change process name | 
|---|
| 33 | ; | 
|---|
| 34 | RESTART ; | 
|---|
| 35 | H 5 ;Hibernate so caller can clear (*p16,*p35) | 
|---|
| 36 | N $ESTACK S $ETRAP="D ETRAP^XWBTCPL" | 
|---|
| 37 | S DONE=0,X=0,XWBTIME=5,XWBTIME(1)=5 | 
|---|
| 38 | S XWBOS=$S(^%ZOSF("OS")["DSM":"DSM",^("OS")["OpenM":"OpenM",^("OS")["GT.M":"GTM",^("OS")["MSM":"MSM",1:"") | 
|---|
| 39 | S XWBT("BF")=$S(XWBOS="GT.M":"#",1:"!") ;(*p35) | 
|---|
| 40 | ; | 
|---|
| 41 | S %T=0 ;Check for Open success (*p35) | 
|---|
| 42 | ;DSM | 
|---|
| 43 | I XWBOS="DSM" O XWBTSKT:TCPCHAN:5 S %T=$T ;Open listener | 
|---|
| 44 | ;Cache, Terminator = $C(4)512 buffers, queue = 10 | 
|---|
| 45 | I XWBOS="OpenM" S XWBTDEV="|TCP|"_XWBTSKT O XWBTDEV:(:XWBTSKT:"A":$C(4):512:512:10):5 S %T=$T ;(*p35) | 
|---|
| 46 | ;GT.M (*p35) | 
|---|
| 47 | I XWBOS="GTM" D | 
|---|
| 48 | . S @("$ZINTERRUPT=""I $$JOBEXAM^ZU($ZPOSITION)""") | 
|---|
| 49 | . S XWBTDEV="SKD$"_$J,XWBTSKT=XWBTSKT | 
|---|
| 50 | . O XWBTDEV:(ZLISTEN=XWBTSKT_":TCP":NODELIMITER:ATTACH="listener"):5:"SOCKET" S %T=$T Q:'%T | 
|---|
| 51 | . U XWBTDEV S XWBTDEV("LISTENER")=$KEY | 
|---|
| 52 | . W /LISTEN(1) | 
|---|
| 53 | . U XWBTDEV S XWBTDEV("STATUS")=$KEY | 
|---|
| 54 | . Q | 
|---|
| 55 | ;Check if got device Open | 
|---|
| 56 | I '%T D LOG^XWBDLOG("Open "_XWBTSKT_" Fail") Q  ;(*p35) | 
|---|
| 57 | ; | 
|---|
| 58 | I XWBDEBUG D LOG^XWBDLOG("Port Open: "_XWBTSKT) | 
|---|
| 59 | F  D  Q:DONE | 
|---|
| 60 | . S DONE=0 | 
|---|
| 61 | . ; -- listen for connect & get the initial message from the client | 
|---|
| 62 | . I XWBOS="DSM" U XWBTSKT S XWBTIME=60 ;Will wait at read | 
|---|
| 63 | . I XWBOS="MSM" S XWBTDEV=56 O 56 U 56::"TCP" W /SOCKET("",XWBTSKT) | 
|---|
| 64 | . I XWBOS="OpenM" U XWBTDEV R *X ;Cache will wait here for connection | 
|---|
| 65 | . I XWBOS="GTM" D | 
|---|
| 66 | . . K XWBTDEV("SOCKET") | 
|---|
| 67 | . . F  D  Q:$D(XWBTDEV("SOCKET")) | 
|---|
| 68 | . . . ;Wait for connection, $KEY will be "CONNECT|socket_handle|remote_ipaddress" | 
|---|
| 69 | . . . U XWBTDEV W /WAIT(10) S XWBTDEV("KEY")=$KEY | 
|---|
| 70 | . . . I XWBTDEV("KEY")="" Q | 
|---|
| 71 | . . . S XWBTDEV("SOCKET")=$P(XWBTDEV("KEY"),"|",2) | 
|---|
| 72 | . . . S (XWBTDEV("IP"),IO("GTM-IP"))=$P(XWBTDEV("KEY"),"|",3) | 
|---|
| 73 | . . . U XWBTDEV:(SOCKET=XWBTDEV("SOCKET"):WIDTH=512:NOWRAP:EXCEPTION="GOTO ETRAP") | 
|---|
| 74 | . . . Q | 
|---|
| 75 | . . Q | 
|---|
| 76 | . ;========================MAIN LOOP======================= | 
|---|
| 77 | . ;(*p35) change to use MSG, MSG1 and MSG2 | 
|---|
| 78 | . S (MSG,MSG1,MSG2,XWBRBUF)="" | 
|---|
| 79 | . ;F XCNT=0:0 R MSG1#1:XWBTIME Q:$T  I '$T S XCNT=XCNT+1 Q:XCNT>5 | 
|---|
| 80 | . F XCNT=0:0 S MSG1=$$BREAD^XWBRW(1,XWBTIME,1) Q:$L(MSG1)  S XCNT=XCNT+1 Q:XCNT>5 | 
|---|
| 81 | . Q:XCNT>5 | 
|---|
| 82 | . I MSG1'="{" D RELEASE(0) Q  ;Not the right start so Close. | 
|---|
| 83 | . S MSG1=MSG1_$$BREAD^XWBRW(4,,1) IF (MSG1'="{XWB}") D RELEASE(0) Q | 
|---|
| 84 | . S MSG1=MSG1_$$BREAD^XWBRW(6) | 
|---|
| 85 | . I $E(MSG1,11)="|" D | 
|---|
| 86 | . . S VL=$$BREAD^XWBRW(1),VL=$A(VL) | 
|---|
| 87 | . . S XWBVER=$$BREAD^XWBRW(VL) | 
|---|
| 88 | . . S LEN=$$BREAD^XWBRW(5) | 
|---|
| 89 | . . S MSG=$$BREAD^XWBRW(+LEN) | 
|---|
| 90 | . E  S X=$E(MSG1,11),LEN=$E(MSG1,6,10)-1,MSG2=$$BREAD^XWBRW(LEN),MSG=X_MSG2,XWBVER=0 | 
|---|
| 91 | . ; -- msg should be:  action^client IP^client port^token | 
|---|
| 92 | . I XWBDEBUG D LOG^XWBDLOG("Hdr:"_MSG1_" Msg:"_MSG) ;(*p35) | 
|---|
| 93 | . ; | 
|---|
| 94 | . ; -- if the action is TCPconnect (usual case) | 
|---|
| 95 | . I $P(MSG,"^")="TCPconnect" D | 
|---|
| 96 | . . N DZ,%T S DZ="",%T=0,RETRY=$S($G(RETRY)>1:RETRY-1,1:0) ;(*p7*) | 
|---|
| 97 | . . ;Get the peer and use that IP, Allow use thru a NAT box. | 
|---|
| 98 | . . S NATIP=$$GETPEER^%ZOSV I $L(NATIP) S $P(MSG,"^",2)=NATIP ;(*p35) | 
|---|
| 99 | . . I '$$NEWJOB D QSND("reject") Q  ;(*p7,*p35) | 
|---|
| 100 | . . I XWBDEBUG>1 D LOG^XWBDLOG("JOB: "_MSG) | 
|---|
| 101 | . . ;Job a Server, X should be null | 
|---|
| 102 | . . J EN^XWBTCPC($P(MSG,"^",2),$P(MSG,"^",3),$P(DZ,"^"),XWBVER,$P(MSG,"^",4))::5 S %T=$T | 
|---|
| 103 | . . I %T D QSND("accept") ;(*p35) | 
|---|
| 104 | . . I '%T  D QSND("reject") ;(*p35) | 
|---|
| 105 | . ; | 
|---|
| 106 | . ; -- if the action is TCPdebug (when msg handler run interactively) | 
|---|
| 107 | . I $P(MSG,"^")="TCPdebug" D QSND("accept") ;(*p35) | 
|---|
| 108 | . ; | 
|---|
| 109 | . ; -- if the action is TCPshutdown, this listener will quit if the | 
|---|
| 110 | . ;    stop flag has been set.  This request comes from an M process. | 
|---|
| 111 | . I $P(MSG,"^")="TCPshutdown" S DONE=1 D QSND^XWBRW("ack") | 
|---|
| 112 | . D RELEASE(0) ;Now release the connection. (*p7*) | 
|---|
| 113 | . Q | 
|---|
| 114 | ; -- loop end | 
|---|
| 115 | ; | 
|---|
| 116 | S %=$$SEMAPHOR(XWBTSKT,"UNLOCK") ; destroy 'running flag' | 
|---|
| 117 | D LOG^XWBDLOG("Exit") | 
|---|
| 118 | D UPDTREC(XWBTSKT,6) ;updt RPC BROKER SITE PARAMETER record as STOPPED | 
|---|
| 119 | S $ETRAP="" ;(*p35) Turn off error trap | 
|---|
| 120 | IF XWBOS="DSM" C XWBTSKT ;Do Close last in case it gets an error | 
|---|
| 121 | Q | 
|---|
| 122 | ; | 
|---|
| 123 | QSND(STR) ;Write output (*p35) | 
|---|
| 124 | D QSND^XWBRW(STR),LOG^XWBDLOG(STR) | 
|---|
| 125 | Q | 
|---|
| 126 | ; | 
|---|
| 127 | ETRAP ; -- on trapped error, send error info to client | 
|---|
| 128 | N XWBERC,XWBERR S $ETRAP="D ^%ZTER J EN^XWBTCPL($G(XWBTSKT)) HALT" | 
|---|
| 129 | S XWBERC=$$EC^%ZOSV,XWBERR=$C(24)_"M  ERROR="_XWBERC_$C(13,10)_"LAST REF="_$$LGR^%ZOSV | 
|---|
| 130 | D ^%ZTER ;Record error and clear $ECODE | 
|---|
| 131 | D LOG^XWBDLOG("Error: "_$E(XWBERC,1,200)) | 
|---|
| 132 | S RETRY=$G(RETRY)+1 H 3+(RETRY\5) ;(*p7*) Slow down but never stop | 
|---|
| 133 | ;Halt if DSM DUPNAME | 
|---|
| 134 | I XWBERC["F-DUPLNAM" D  HALT | 
|---|
| 135 | . S %=$$SEMAPHOR(XWBTSKT,"UNLOCK") ; destroy 'running flag' | 
|---|
| 136 | . D UPDTREC(XWBTSKT,6) ;updt RPC BROKER SITE PARAMETER record as STOPPED | 
|---|
| 137 | . Q | 
|---|
| 138 | S XWBDEBUG=$G(XWBDEBUG) | 
|---|
| 139 | ;Set new trap | 
|---|
| 140 | S $ETRAP="Q:($ESTACK&'$QUIT)  Q:$ESTACK -9 S $ECODE="""" G RESTART^XWBTCPL" | 
|---|
| 141 | ; | 
|---|
| 142 | I (XWBERC["READ")!(XWBERC["WRITE")!(XWBERC["SYSTEM-F") G ETRAPX | 
|---|
| 143 | IF XWBOS="DSM" D | 
|---|
| 144 | . I $D(XWBTLEN),XWBTLEN,XWBERC'["SYSTEM-F" D QSND(XWBERR) ;(p35) | 
|---|
| 145 | IF XWBOS="OpenM",XWBERC'["<WRITE>" D QSND(XWBERR) ;(*p7,35*) | 
|---|
| 146 | IF XWBOS="MSM" D QSND(XWBERR) ;(*p7,35*) | 
|---|
| 147 | ETRAPX D RELEASE(1) ;Now close the connection. (*p7*) | 
|---|
| 148 | I XWBOS="DSM" H 15 ;Wait for device to close | 
|---|
| 149 | S $ECODE=",U1," Q  ;Pass error up to pop stack. | 
|---|
| 150 | ; | 
|---|
| 151 | FLUSH ;Flush the input buffer | 
|---|
| 152 | F  R X:0 Q:'$T | 
|---|
| 153 | Q | 
|---|
| 154 | ; | 
|---|
| 155 | RELEASE(%) ;Now release the connection. (*p7*) | 
|---|
| 156 | ;Parameter is zero to Release, one to Close | 
|---|
| 157 | I XWBOS="DSM" D  Q  ;(*p35) | 
|---|
| 158 | . I $G(%) C XWBTSKT Q | 
|---|
| 159 | . U XWBTSKT:DISCONNECT ; release this socket | 
|---|
| 160 | I XWBOS="OpenM" D  Q  ;(*p35) | 
|---|
| 161 | . I $G(%) C XWBTDEV Q | 
|---|
| 162 | . W *-2 ;Release the socket | 
|---|
| 163 | I XWBOS="GTM" D  Q  ;(*p35) | 
|---|
| 164 | . I $G(%) C XWBTDEV Q | 
|---|
| 165 | . C XWBTDEV:(SOCKET=XWBTDEV("SOCKET")) ;release the socket | 
|---|
| 166 | I XWBOS="MSM" C 56 | 
|---|
| 167 | Q | 
|---|
| 168 | ; | 
|---|
| 169 | UPDTREC(XWBTSKT,STATE,XWBENV) ; -- update STATUS field and ^%ZIS X-ref of the | 
|---|
| 170 | ;RPC BROKER SITE PARAMETER file | 
|---|
| 171 | ;XWBTSKT: listener port | 
|---|
| 172 | N C,XWBOXIEN,XWBPOIEN,XWBFDA | 
|---|
| 173 | S C=",",U="^" | 
|---|
| 174 | I $G(XWBENV)'="" S Y=XWBENV | 
|---|
| 175 | E  D GETENV^%ZOSV ;get Y=UCI^VOL^NODE^BOXLOOKUP of current system | 
|---|
| 176 | ;I STATE=3 S ^%ZIS(8994.171,"RPCB Listener",$P(Y,U,2),$P(Y,U),$P(Y,U,4),XWBTSKT)=$J | 
|---|
| 177 | ;I STATE=6 K ^%ZIS(8994.171,"RPCB Listener",$P(Y,U,2),$P(Y,U),$P(Y,U,4),XWBTSKT) | 
|---|
| 178 | ; | 
|---|
| 179 | S XWBOXIEN=$$FIND1^DIC(8994.17,",1,","",$P(Y,U,4)) ;find rec for box | 
|---|
| 180 | S XWBPOIEN=$$FIND1^DIC(8994.171,C_XWBOXIEN_",1,","",XWBTSKT) | 
|---|
| 181 | D:XWBPOIEN>0  ;update STATUS field if entry was found | 
|---|
| 182 | . D FDA^DILF(8994.171,XWBPOIEN_C_XWBOXIEN_C_1_C,1,"R",STATE,"XWBFDA") | 
|---|
| 183 | . D FILE^DIE("","XWBFDA") | 
|---|
| 184 | Q | 
|---|
| 185 | ; | 
|---|
| 186 | ; | 
|---|
| 187 | SEMAPHOR(XWBTSKT,XWBACT) ;Lock/Unlock listener semaphore | 
|---|
| 188 | ;XWBTSKT: listener port, XWBACT: "LOCK" | "UNLOCK" action to perform | 
|---|
| 189 | ;if LOCK is requested, it will be attempted with 1 sec timeout and if | 
|---|
| 190 | ;lock was obtained RESULT will be 1, otherwise it will be 0.  For | 
|---|
| 191 | ;unlock RESULT will always be 1. | 
|---|
| 192 | N RESULT | 
|---|
| 193 | S U="^",RESULT=1 | 
|---|
| 194 | D GETENV^%ZOSV ;get Y=UCI^VOL^NODE^BOXLOOKUP of current system | 
|---|
| 195 | I XWBACT="LOCK" D | 
|---|
| 196 | . L +^%ZIS(8994.171,"RPCB Listener",$P(Y,U,2),$P(Y,U),$P(Y,U,4),XWBTSKT):1 | 
|---|
| 197 | . S RESULT=$T | 
|---|
| 198 | E  L -^%ZIS(8994.171,"RPCB Listener",$P(Y,U,2),$P(Y,U),$P(Y,U,4),XWBTSKT) | 
|---|
| 199 | Q RESULT | 
|---|
| 200 | ; | 
|---|
| 201 | NEWJOB() ;Check if OK to start a new job, Return 1 if OK, 0 if not OK. | 
|---|
| 202 | N X,Y,XQVOL,XUVOL | 
|---|
| 203 | S X=$O(^XTV(8989.3,1,4,"B",XWBVOL,0)),XUVOL=$S(X>0:^XTV(8989.3,1,4,X,0),1:"ROU^y^1"),XQVOL=XWBVOL | 
|---|
| 204 | S X=$$INHIBIT^XUSRB ;Returns 1 if new logons are inhibited. | 
|---|
| 205 | Q 'X | 
|---|