[Idle-dev] CVS: idle PyShell.py,1.20,1.21 rpc.py,1.3,1.4 run.py,1.3,1.4
Kurt B. Kaiser
kbk@users.sourceforge.net
Thu, 25 Jul 2002 17:06:45 -0700
Update of /cvsroot/idlefork/idle
In directory usw-pr-cvs1:/tmp/cvs-serv13932
Modified Files:
PyShell.py rpc.py run.py
Log Message:
Reverse the RPC socket connection: Python execution server connects to
Idle client and localhost origin of connection is verified by client.
M PyShell.py
M rpc.py
M run.py
Index: PyShell.py
===================================================================
RCS file: /cvsroot/idlefork/idle/PyShell.py,v
retrieving revision 1.20
retrieving revision 1.21
diff -C2 -r1.20 -r1.21
*** PyShell.py 11 Jul 2002 04:33:41 -0000 1.20
--- PyShell.py 26 Jul 2002 00:06:41 -0000 1.21
***************
*** 194,202 ****
port = 8833
addr = ("localhost", port)
w = ['-W' + s for s in sys.warnoptions]
args = [sys.executable] + w + ["-c", "__import__('run').main()",
str(port)]
self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
! for i in range(5):
time.sleep(i)
try:
--- 194,206 ----
port = 8833
addr = ("localhost", port)
+ # Spawn the Python execution "server"
w = ['-W' + s for s in sys.warnoptions]
args = [sys.executable] + w + ["-c", "__import__('run').main()",
str(port)]
self.rpcpid = os.spawnv(os.P_NOWAIT, args[0], args)
! # Idle starts listening for connection on localhost, retry since
! # Idle may be restarted before port is available for rebinding
! # XXX 25 July 2002 KBK Find out what is causing the delayed release!
! for i in range(12):
time.sleep(i)
try:
***************
*** 204,215 ****
break
except socket.error, err:
! if i > 3:
! print >>sys.__stderr__, "Socket error:", err, "; retry..."
else:
- # XXX Make this a dialog? #GvR
- print >>sys.__stderr__, "Can't spawn subprocess!"
- # XXX Add Stephen's error msg, resolve the two later... KBK 09Jun02
display_port_binding_error()
return
self.rpcclt.register("stdin", self.tkconsole)
self.rpcclt.register("stdout", self.tkconsole.stdout)
--- 208,221 ----
break
except socket.error, err:
! if i < 5:
! print>>sys.__stderr__, ". ",
! else:
! print>>sys.__stderr__,"\nIdle socket error: " + err[1]\
! + ", retrying..."
else:
display_port_binding_error()
return
+ # Accept the connection from the Python execution server
+ self.rpcclt.accept()
self.rpcclt.register("stdin", self.tkconsole)
self.rpcclt.register("stdout", self.tkconsole.stdout)
Index: rpc.py
===================================================================
RCS file: /cvsroot/idlefork/idle/rpc.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** rpc.py 26 Jun 2002 02:32:09 -0000 1.3
--- rpc.py 26 Jul 2002 00:06:41 -0000 1.4
***************
*** 1,21 ****
! # ASCII-art documentation
! #
! # +---------------------------------+ +----------+
! # | SocketServer.BaseRequestHandler | | SocketIO |
! # +---------------------------------+ +----------+
! # ^ ^ ^
! # | | |
! # | + -------------------+ |
! # | | |
! # +-------------------------+ +-----------------+
! # | RPCHandler | | RPCClient |
! # |-------------------------| |-----------------|
! # | register() | | remotecall() |
! # | unregister() | | register() |
! # | | | unregister() |
! # | | | get_remote_proxy|
! # +-------------------------+ +-----------------+
! #
! import sys
import socket
import select
--- 1,32 ----
! """RPC Implemention, originally written for the Python Idle IDE
!
! For security reasons, GvR requested that Idle's Python execution server process
! connect to the Idle process, which listens for the connection. Since Idle has
! has only one client per server, this was not a limitation.
!
! +---------------------------------+ +-------------+
! | SocketServer.BaseRequestHandler | | SocketIO |
! +---------------------------------+ +-------------+
! ^ | register() |
! | | unregister()|
! | +-------------+
! | ^ ^
! | | |
! | + -------------------+ |
! | | |
! +-------------------------+ +-----------------+
! | RPCHandler | | RPCClient |
! | [attribute of RPCServer]| | |
! +-------------------------+ +-----------------+
!
! The RPCServer handler class is expected to provide register/unregister methods.
! RPCHandler inherits the mix-in class SocketIO, which provides these methods.
!
! See the Idle run.main() docstring for further information on how this was
! accomplished in Idle.
!
! """
!
! import sys
import socket
import select
***************
*** 56,93 ****
if handlerclass is None:
handlerclass = RPCHandler
! # XXX KBK 25Jun02 Not used in Idlefork, see register/unregister note below.
# self.objtable = objecttable
SocketServer.TCPServer.__init__(self, addr, handlerclass)
! # XXX KBK 25Jun02 Following method is not used (yet)
! # def verify_request(self, request, client_address):
! # host, port = client_address
! # if host != "127.0.0.1":
! # print "Disallowed host:", host
! # return 0
! # else:
! # return 1
!
! # XXX KBK 25Jun02 The handlerclass is expected to provide register/unregister
! # methods. In Idle, RPCServer is instantiated with
! # handlerclass MyHandler, which in turn inherits the
! # register/unregister methods from the mix-in class SocketIO.
! # It is true that this is asymmetric with the RPCClient's use
! # of register/unregister, but I guess that's how a SocketServer
! # is supposed to work.
!
! # Exactly how this gets set up is convoluted. When the
! # TCPServer is instantiated, it creates an instance of
! # run.MyHandler and calls its handle() method. handle()
! # instantiates a run.Executive, passing it a reference to the
! # MyHandler object. That reference is saved as an attribute of
! # the Executive instance. The Executive methods have access to
! # the reference and can pass it on to entities that they
! # command (e.g. RemoteDebugger.Debugger.start_debugger()). The
! # latter, in turn, can call MyHandler(SocketIO)
! # register/unregister methods via the reference to register and
! # unregister themselves. Whew.
! # The following two methods are not currently used in Idlefork.
# def register(self, oid, object):
# self.objtable[oid] = object
--- 67,93 ----
if handlerclass is None:
handlerclass = RPCHandler
! # XXX KBK 25Jun02 Not used in Idlefork.
# self.objtable = objecttable
SocketServer.TCPServer.__init__(self, addr, handlerclass)
! def server_bind(self):
! "Override TCPServer method, no bind() phase for connecting entity"
! pass
!
! def server_activate(self):
! """Override TCPServer method, connect() instead of listen()
!
! Due to the reversed connection, self.server_address is actually the
! address of the Idle Client to which we are connecting.
!
! """
! self.socket.connect(self.server_address)
!
! def get_request(self):
! "Override TCPServer method, return already connected socket"
! return self.socket, self.server_address
!
! # XXX The following two methods are not currently used in Idlefork.
# def register(self, oid, object):
# self.objtable[oid] = object
***************
*** 365,368 ****
--- 365,370 ----
self.statelock.release()
continue
+
+ #----------------- end class SocketIO --------------------
class RemoteObject:
***************
*** 389,401 ****
SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr)
- def setup(self):
- SocketServer.BaseRequestHandler.setup(self)
- print >>sys.__stderr__, "Connection from", self.client_address
-
- def finish(self):
- print >>sys.__stderr__, "End connection from", self.client_address
- SocketServer.BaseRequestHandler.finish(self)
-
def handle(self):
self.mainloop()
--- 391,396 ----
SocketServer.BaseRequestHandler.__init__(self, sock, addr, svr)
def handle(self):
+ "handle() method required by SocketServer"
self.mainloop()
***************
*** 405,414 ****
class RPCClient(SocketIO):
! nextseq = 1 # Requests coming from the client are odd
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
! sock = socket.socket(family, type)
! sock.connect(address)
! SocketIO.__init__(self, sock)
def get_remote_proxy(self, oid):
--- 400,418 ----
class RPCClient(SocketIO):
! nextseq = 1 # Requests coming from the client are odd numbered
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
! self.sock = socket.socket(family, type)
! self.sock.bind(address)
! self.sock.listen(1)
!
! def accept(self):
! newsock, address = self.sock.accept()
! if address[0] == '127.0.0.1':
! print>>sys.__stderr__, "Idle accepted connection from ", address
! SocketIO.__init__(self, newsock)
! else:
! print>>sys.__stderr__, "Invalid host: ", address
! raise socket.error
def get_remote_proxy(self, oid):
***************
*** 478,481 ****
--- 482,486 ----
def testServer(addr):
+ # XXX 25 Jul 02 KBK needs update to use rpc.py register/unregister methods
class RemotePerson:
def __init__(self,name):
***************
*** 506,513 ****
def testClient(addr):
!
! #
! # demonstrates RPC Client
! #
import time
clt=RPCClient(addr)
--- 511,516 ----
def testClient(addr):
! "demonstrates RPC Client"
! # XXX 25 Jul 02 KBK needs update to use rpc.py register/unregister methods
import time
clt=RPCClient(addr)
***************
*** 524,528 ****
print
time.sleep(2)
-
# demonstrates remote server calling local instance
class LocalPerson:
--- 527,530 ----
Index: run.py
===================================================================
RCS file: /cvsroot/idlefork/idle/run.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** run.py 26 Jun 2002 02:32:09 -0000 1.3
--- run.py 26 Jul 2002 00:06:42 -0000 1.4
***************
*** 1,6 ****
--- 1,24 ----
import sys
+ import time
+ import socket
import rpc
def main():
+ """Start the Python execution server in a subprocess
+
+ In Idle, RPCServer is instantiated with handlerclass MyHandler, which
+ inherits register/unregister methods from RPCHandler via the mix-in class
+ SocketIO.
+
+ When the RPCServer is instantiated, the TCPServer initialization creates an
+ instance of run.MyHandler and calls its handle() method. handle()
+ instantiates a run.Executive, passing it a reference to the MyHandler
+ object. That reference is saved as an attribute of the Executive instance.
+ The Executive methods have access to the reference and can pass it on to
+ entities that they command (e.g. RemoteDebugger.Debugger.start_debugger()).
+ The latter, in turn, can call MyHandler(SocketIO) register/unregister
+ methods via the reference to register and unregister themselves.
+
+ """
port = 8833
if sys.argv[1:]:
***************
*** 8,12 ****
sys.argv[:] = [""]
addr = ("localhost", port)
! svr = rpc.RPCServer(addr, MyHandler)
svr.handle_request() # A single request only
--- 26,43 ----
sys.argv[:] = [""]
addr = ("localhost", port)
! for i in range(12):
! time.sleep(i)
! try:
! svr = rpc.RPCServer(addr, MyHandler)
! break
! except socket.error, err:
! if i < 5:
! print>>sys.__stderr__, ".. ",
! else:
! print>>sys.__stderr__,"\nPython subprocess socket error: "\
! + err[1] + ", retrying...."
! else:
! print>>sys.__stderr__, "\nConnection to Idle failed, exiting."
! sys.exit()
svr.handle_request() # A single request only