source: cprs/branches/tmg-cprs/m_files/TMGKERN2.m~@ 796

Last change on this file since 796 was 796, checked in by Kevin Toppenberg, 14 years ago

Initial upload

File size: 10.1 KB
Line 
1TMGKERN2 ;TMG/kst/OS Specific functions ;11/21/09
2 ;;1.0;TMG-LIB;**1**;11/21/09
3 ;
4 ;"TMG KERNEL FUNCTIONS -- 2
5 ;"This module is primarly for functions to support a SOCKET
6 ;" connection between two different VistA instances. One running
7 ;" as a server, and the other as a client.
8 ;"I.e. functions that are OS specific.
9 ;"Kevin Toppenberg MD
10 ;"GNU General Public License (GPL) applies
11 ;"11/21/09
12 ;
13RUNSERVER(PORT,TMGMSGFN,TMGVERBOSE)
14 ;"Purpose: To open up a socket that will listen to requests from a client.
15 ;"Input: Port -- the port to listen on
16 ;" TMGMSGFN -- the NAME of a function that will handle incoming
17 ;" messages. E.g. 'HANDLMSG^MOD1'
18 ;" This function will be called as follows:
19 ;" xecute "DO "_TMGMSGFN_"(TMGCLIENT)"
20 ;" So the function must accept at least 1 parameter.
21 ;" TMGVERBOSE -- If 1 then some output will be show to console.
22 ;"Results: 1 if successful, -1^Error Message if failed.
23 ;"NOTE: This will be messaging protocol.
24 ;" #HELLO# will be sent on startup (possibly preceeded by 2 blank lines)
25 ;" #BYE# will be sent when server is quitting
26 ;" Server will respond to query of #BYE# by quitting.
27 ;" Server will turn control over to the message-handler-fn, allowing it to write
28 ;" out as many lines as it wants.
29 ;" After message-handler-fn returns, the server will send #OK# to signal done.
30 ;"
31 NEW RESULT,TMGDELIM,TMGTCPDEV,TMGTIMEOUT
32 NEW TMGCLIENT,TMGANSWR,TMGCODE
33 ;
34 SET RESULT=1 ;"Default of success
35 IF +$GET(PORT)'>0 DO GOTO RSVRDN
36 . SET RESULT="-1^Invalid port number passed. Received: "_$GET(PORT)
37 IF $GET(TMGMSGFN)="" DO GOTO RSVRDN
38 . SET RESULT="-1^No Message handling function passed."
39 IF $TEXT(@TMGMSGFN)="" DO GOTO RSVRDN
40 . SET RESULT="-1^Message handler ["_TMGMSGFN_"] appears invalid"
41 SET PORT=+$GET(PORT)
42 SET TMGDELIM=$CHAR(13)
43 SET TMGTCPDEV="server$"_$JOB
44 SET TMGTIMEOUT=30
45 SET TMGCODE="DO "_TMGMSGFN_"(TMGCLIENT)"
46 SET TMGVERBOSE=+$GET(TMGVERBOSE)
47 ;
48 OPEN TMGTCPDEV:(ZLISTEN=PORT_":TCP":attach="server":DELIMITER=TMGDELIM):TMGTIMEOUT:"SOCKET"
49 IF $TEST=0 DO goto RSVRDN
50 . SET RESULT="-1^Attempts to open server failed (timedout)"
51 USE TMGTCPDEV
52 WRITE /listen(1)
53 WRITE /wait(TMGTIMEOUT)
54 WRITE "#HELLO#",!
55 ;
56L1 ;"Main Listen-Reply loop
57 NEW TMGCLIENT,TMGI,TMGDONE
58 SET TMGDONE=-1,TMGI=1
59 FOR DO QUIT:(TMGDONE>0)!(TMGI>100)!(TMGCLIENT="#BYE#")
60 . USE TMGTCPDEV
61 . READ TMGCLIENT:TMGTIMEOUT
62 . IF ($TEST=0)!(TMGCLIENT="") DO QUIT
63 . . SET TMGDONE=TMGDONE+1
64 . . WRITE "#BYE#",!
65 . IF TMGCLIENT="#ENQ#" WRITE "#ACK#",! QUIT
66 . IF TMGCLIENT="#BYE#" WRITE "#BYE#",! QUIT
67 . SET TMGI=TMGI+1
68 . DO
69 . . NEW $etrap
70 . . SET $etrap="write ""<Error in message handler>"",!,$ZSTATUS,! set $etrap="""",$ecode="""""
71 . . XECUTE TMGCODE
72 . USE TMGTCPDEV ;"Ensure handler didn't redirect $IO
73 . WRITE "#OK#",! ;"Send message to indicate done sending reply (will allow multi line responses)
74 . use $P
75 . read *TMGDONE:0
76 . IF TMGVERBOSE DO
77 . . if TMGI#10=1 write "+"
78 . . else write "."
79 ;
80 CLOSE TMGTCPDEV
81 ;
82RSVRDN USE $P
83 QUIT RESULT
84 ;
85 ;
86RUNCLIENT(HOST,PORT) ;"NOTE: meant to be run as a background process
87 ;"Purpose: Establish a connection with specified server. Then maintain connection,
88 ;" sending queries to server, and returning results. Will take as input
89 ;" a messaging global ^TMG("TMP","TCP",$J,"TS",<index>)=<query> TS=ToServer
90 ;" And replies will be stored in ^TMG("TMP","TCP",$J,"FS",<index>)=<query> FS=FromServer
91 ;"Input: HOST -- the IP address, (or name for DNS lookup) of the server.
92 ;" PORT -- the port that the server is listening on.
93 ;"Result: none
94 ;"Output: Results will be stored in ^TMG("TMP","TCP",$J,"RESULT")=<result>
95 ;" 1 -- if successful, -1^Error Message if failed.
96 ;"
97 NEW RESULT,TMGDELIM,TMGTCPDEV,TMGTIMEOUT
98 ;"Setup vars
99 SET TMGTCPDEV="client$"_$JOB
100 SET TMGTIMEOUT=30
101 KILL ^TMG("TMP","TCP",$J,"RESULT")
102 SET RESULT=1
103 ;"Validate input
104 IF +$GET(PORT)'>0 DO GOTO RCLDN
105 . SET RESULT="-1^Valid port number passed. Received: "_$GET(PORT)
106 IF $GET(HOST)="" DO GOTO RCLDN
107 . SET RESULT="-1^No Host passed."
108 SET PORT=+$GET(PORT)
109 IF PORT'>0 DO GOTO RCLDN
110 . SET RESULT="-1^Invalid port: ["_PORT_"]"
111 ;"Open up the TCP/IP connection
112 OPEN TMGTCPDEV:(CONNECT=HOST_":"_PORT_":TCP":ATTACH="client":DELIMITER=$CHAR(13)):TMGTIMEOUT:"SOCKET"
113 IF $TEST=0 DO GOTO RCLDN
114 . SET RESULT="-1^Error on OPEN of SOCKET"
115 USE TMGTCPDEV
116 ;"Make sure server is ready to send information.
117 NEW TMGI,SRVREPLY
118 FOR TMGI=1:1:3 DO QUIT:(SRVREPLY="#HELLO#")
119 . READ SRVREPLY:TMGTIMEOUT
120 IF SRVREPLY'="#HELLO#" DO GOTO RCLDN
121 . SET RESULT="-1^Failed to get a '#HELLO#' from server"
122 SET ^TMG("TMP","TCP",$J,"RESULT")=$GET(RESULT)
123 ;
124 ;"Now process messaging.
125RC1 NEW TSREF SET TSREF=$NAME(^TMG("TMP","TCP",$J,"TS"))
126 NEW FSREF SET FSREF=$NAME(^TMG("TMP","TCP",$J,"FS"))
127 NEW QUERY SET QUERY=""
128 NEW TMGIDLE SET TMGIDLE=0
129 FOR DO quit:(QUERY="#BYE#")!(SRVREPLY="#BYE#")
130 . SET TMGI=$ORDER(@TSREF@(""))
131 . IF TMGI="" DO ;"Start idle handling
132 . . SET QUERY=""
133 . . SET TMGIDLE=TMGIDLE+1
134 . . HANG 0.1
135 . . IF TMGIDLE<50 QUIT
136 . . SET QUERY="#ENQ#" ;"send an ENQ every 5 seconds of idleness.
137 . . SET TMGIDLE=0
138 . ELSE DO
139 . . SET QUERY=$get(@TSREF@(TMGI))
140 . . KILL @TSREF@(TMGI)
141 . . SET TMGIDLE=0 ;"Reset idle counter
142 . IF QUERY="" QUIT
143 . USE TMGTCPDEV
144 . WRITE QUERY,! ;"send query to server.
145 . FOR DO QUIT:(SRVREPLY="#BYE#")!(SRVREPLY="#OK#")!(SRVREPLY="#ACK#")
146 . . READ SRVREPLY:TMGTIMEOUT ;"read reply.
147 . . IF ($TEST=0)!(SRVREPLY="") SET SRVREPLY="#BYE#"
148 . . IF SRVREPLY="#ACK#" QUIT ;"Don't record ENQ-ACK's
149 . . IF SRVREPLY="#BYE#" QUIT ;"Don't record Termination signal.
150 . . SET TMGI=+$ORDER(@FSREF@(""),-1)
151 . . SET @FSREF@(TMGI+1)=SRVREPLY
152 WRITE "#BYE#",!
153 CLOSE TMGTCPDEV
154 ;
155RCLDN USE $P
156 SET ^TMG("TMP","TCP",$J,"RESULT")=$GET(RESULT)
157 HALT
158 ;
159 ;
160MSGCLIENT(JNUM,QUERY,REPLY,ERROR,TIMEOUT)
161 ;"Purpose: To send messages to background client. So this will be one function
162 ;" that the programmer may interact with. The reason for having the client
163 ;" run as a separate job is so that the server and the client can talk back
164 ;" and forth with ENQ<-->ACK upon either timing out, to keep the connection
165 ;" alive.
166 ;"Input: JNUM -- The job number of the background client process
167 ;" QUERY -- The message to send to the server.
168 ;" REPLY -- PASS BY REFERENCE, AN OUT PARAMETER. Prior data killed.
169 ;" REPLY(1)=<a reply line from server>
170 ;" REPLY(2)=<a reply line from server>
171 ;" REPLY(3)=<a reply line from server>
172 ;" ERROR -- PASS BY REFERENCE, AN OUT PARAMETER. Prior data killed.
173 ;" If error, filled with -1^Message.
174 ;" TIMEOUT -- OPTIONAL. Default=1 (in seconds)
175 ;"Result: none
176 ;
177 KILL ERROR,REPLY
178 NEW RESULT SET RESULT=""
179 SET JNUM=+$GET(JNUM)
180 IF JNUM'>0 SET ERROR="-1^BAD JOB NUMBER" GOTO MSGDN
181 SET QUERY=$GET(QUERY)
182 IF QUERY="" SET ERROR="-1^NO QUERY PROVIDED" GOTO MSGDN
183 SET TIMEOUT=+$GET(TIMEOUT,1)
184 NEW NTIME,STIME SET STIME=$PIECE($H,",",2)
185 NEW TMGI SET TMGI=+$ORDER(^TMG("TMP","TCP",JNUM,"TS",""),-1)
186 SET ^TMG("TMP","TCP",JNUM,"TS",TMGI+1)=QUERY
187 IF QUERY="#BYE#" GOTO MSGDN
188 NEW REPLYI SET REPLYI=1
189 NEW ONELINE SET ONELINE=""
190 FOR DO QUIT:(ONELINE="#OK#")
191 . SET TMGI=$ORDER(^TMG("TMP","TCP",JNUM,"FS",""))
192 . IF TMGI="" DO QUIT
193 . . SET NTIME=$PIECE($H,",",2)
194 . . IF (NTIME-STIME)'<TIMEOUT DO
195 . . . SET ERROR="-1^TIMED OUT WAITING FOR CLIENT TO GET REPLY FROM SERVER"
196 . . . SET ONELINE="#OK#"
197 . SET ONELINE=$GET(^TMG("TMP","TCP",JNUM,"FS",TMGI))
198 . IF ONELINE'="#OK#" SET REPLY(REPLYI)=ONELINE
199 . SET REPLYI=REPLYI+1
200 . KILL ^TMG("TMP","TCP",JNUM,"FS",TMGI)
201MSGDN QUIT
202 ;
203 ;
204CLEARBUF(JNUM,ERROR)
205 ;"Purpose: To remove all messages from message buffer.
206 ;"Input: JNUM -- The job number of the background client process
207 ;" ERROR -- PASS BY REFERENCE, AN OUT PARAMETER. Prior data killed.
208 ;" If error, filled with -1^Message.
209 ;"Result: None
210 ;
211 KILL ERROR
212 SET JNUM=+$GET(JNUM)
213 IF JNUM'>0 SET ERROR="-1^BAD JOB NUMBER" GOTO CLBFDN
214 NEW TMGI
215 FOR DO QUIT:(TMGI="")
216 . SET TMGI=$ORDER(^TMG("TMP","TCP",JNUM,"TS",""))
217 . IF TMGI="" QUIT
218 . KILL ^TMG("TMP","TCP",JNUM,"TS",TMGI)
219 FOR DO QUIT:(TMGI="")
220 . SET TMGI=$ORDER(^TMG("TMP","TCP",JNUM,"FS",""))
221 . IF TMGI="" QUIT
222 . KILL ^TMG("TMP","TCP",JNUM,"FS",TMGI)
223 ;
224CLBFDN QUIT
225 ;
226 ;
227 ;"===================================================================
228 ;"===================================================================
229 ;" Delete later...
230 ;"===================================================================
231 ;"===================================================================
232 ;
233HANDLMSG(MESSAGE)
234 write "Got: ["_MESSAGE_"]. Server is $JOB="_$J,!
235 quit
236 ;
237 ;
Note: See TracBrowser for help on using the repository browser.