| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  | """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. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    +---------------------------------+ +-------------+ | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  |    | socketserver.BaseRequestHandler | | SocketIO    | | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |    +---------------------------------+ +-------------+ | 
					
						
							|  |  |  |                    ^                   | 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 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | import socket | 
					
						
							|  |  |  | import select | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  | import socketserver | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | import struct | 
					
						
							| 
									
										
										
										
											2007-07-20 00:22:32 +00:00
										 |  |  | import pickle | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | import threading | 
					
						
							| 
									
										
										
										
											2008-05-11 19:59:59 +00:00
										 |  |  | import queue | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | import traceback | 
					
						
							| 
									
										
										
										
											2008-05-11 08:55:36 +00:00
										 |  |  | import copyreg | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | import types | 
					
						
							|  |  |  | import marshal | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | def unpickle_code(ms): | 
					
						
							|  |  |  |     co = marshal.loads(ms) | 
					
						
							|  |  |  |     assert isinstance(co, types.CodeType) | 
					
						
							|  |  |  |     return co | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def pickle_code(co): | 
					
						
							|  |  |  |     assert isinstance(co, types.CodeType) | 
					
						
							|  |  |  |     ms = marshal.dumps(co) | 
					
						
							|  |  |  |     return unpickle_code, (ms,) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-08-25 14:08:07 +00:00
										 |  |  | # XXX KBK 24Aug02 function pickling capability not used in Idle | 
					
						
							|  |  |  | #  def unpickle_function(ms): | 
					
						
							|  |  |  | #      return ms | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-08-25 14:08:07 +00:00
										 |  |  | #  def pickle_function(fn): | 
					
						
							|  |  |  | #      assert isinstance(fn, type.FunctionType) | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  | #      return repr(fn) | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 08:55:36 +00:00
										 |  |  | copyreg.pickle(types.CodeType, pickle_code, unpickle_code) | 
					
						
							|  |  |  | # copyreg.pickle(types.FunctionType, pickle_function, unpickle_function) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | BUFSIZE = 8*1024 | 
					
						
							| 
									
										
										
										
											2003-06-05 23:51:29 +00:00
										 |  |  | LOCALHOST = '127.0.0.1' | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  | class RPCServer(socketserver.TCPServer): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, addr, handlerclass=None): | 
					
						
							|  |  |  |         if handlerclass is None: | 
					
						
							|  |  |  |             handlerclass = RPCHandler | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  |         socketserver.TCPServer.__init__(self, addr, handlerclass) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |     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()
 | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |     def get_request(self): | 
					
						
							|  |  |  |         "Override TCPServer method, return already connected socket" | 
					
						
							|  |  |  |         return self.socket, self.server_address | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |     def handle_error(self, request, client_address): | 
					
						
							| 
									
										
										
										
											2003-03-22 19:15:58 +00:00
										 |  |  |         """Override TCPServer method
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Error message goes to __stderr__.  No error message if exiting | 
					
						
							|  |  |  |         normally or socket raised EOF.  Other exceptions not handled in | 
					
						
							|  |  |  |         server code will cause os._exit. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             raise | 
					
						
							|  |  |  |         except SystemExit: | 
					
						
							|  |  |  |             raise | 
					
						
							| 
									
										
										
										
											2003-03-22 19:15:58 +00:00
										 |  |  |         except: | 
					
						
							| 
									
										
										
										
											2003-03-22 20:11:14 +00:00
										 |  |  |             erf = sys.__stderr__ | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print('\n' + '-'*40, file=erf) | 
					
						
							|  |  |  |             print('Unhandled server exception!', file=erf) | 
					
						
							| 
									
										
										
										
											2008-11-29 01:48:47 +00:00
										 |  |  |             print('Thread: %s' % threading.current_thread().name, file=erf) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print('Client Address: ', client_address, file=erf) | 
					
						
							|  |  |  |             print('Request: ', repr(request), file=erf) | 
					
						
							| 
									
										
										
										
											2003-03-22 19:15:58 +00:00
										 |  |  |             traceback.print_exc(file=erf) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print('\n*** Unrecoverable, server exiting!', file=erf) | 
					
						
							|  |  |  |             print('-'*40, file=erf) | 
					
						
							| 
									
										
										
										
											2003-03-22 20:11:14 +00:00
										 |  |  |             os._exit(0) | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  | #----------------- end class RPCServer -------------------- | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | objecttable = {} | 
					
						
							| 
									
										
										
										
											2008-05-11 19:59:59 +00:00
										 |  |  | request_queue = queue.Queue(0) | 
					
						
							|  |  |  | response_queue = queue.Queue(0) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  | class SocketIO(object): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |     nextseq = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def __init__(self, sock, objtable=None, debugging=None): | 
					
						
							| 
									
										
										
										
											2008-06-13 02:00:47 +00:00
										 |  |  |         self.sockthread = threading.current_thread() | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         if debugging is not None: | 
					
						
							|  |  |  |             self.debugging = debugging | 
					
						
							|  |  |  |         self.sock = sock | 
					
						
							|  |  |  |         if objtable is None: | 
					
						
							|  |  |  |             objtable = objecttable | 
					
						
							|  |  |  |         self.objtable = objtable | 
					
						
							|  |  |  |         self.responses = {} | 
					
						
							|  |  |  |         self.cvars = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         sock = self.sock | 
					
						
							|  |  |  |         self.sock = None | 
					
						
							|  |  |  |         if sock is not None: | 
					
						
							|  |  |  |             sock.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def exithook(self): | 
					
						
							|  |  |  |         "override for specific exit action" | 
					
						
							|  |  |  |         os._exit() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def debug(self, *args): | 
					
						
							|  |  |  |         if not self.debugging: | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2008-11-29 01:48:47 +00:00
										 |  |  |         s = self.location + " " + str(threading.current_thread().name) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         for a in args: | 
					
						
							|  |  |  |             s = s + " " + str(a) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print(s, file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def register(self, oid, object): | 
					
						
							|  |  |  |         self.objtable[oid] = object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def unregister(self, oid): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             del self.objtable[oid] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def localcall(self, seq, request): | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  |         self.debug("localcall:", request) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             how, (oid, methodname, args, kwargs) = request | 
					
						
							|  |  |  |         except TypeError: | 
					
						
							|  |  |  |             return ("ERROR", "Bad request format") | 
					
						
							| 
									
										
										
										
											2006-08-22 15:45:46 +00:00
										 |  |  |         if oid not in self.objtable: | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |             return ("ERROR", "Unknown object id: %r" % (oid,)) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         obj = self.objtable[oid] | 
					
						
							|  |  |  |         if methodname == "__methods__": | 
					
						
							|  |  |  |             methods = {} | 
					
						
							|  |  |  |             _getmethods(obj, methods) | 
					
						
							|  |  |  |             return ("OK", methods) | 
					
						
							|  |  |  |         if methodname == "__attributes__": | 
					
						
							|  |  |  |             attributes = {} | 
					
						
							|  |  |  |             _getattributes(obj, attributes) | 
					
						
							|  |  |  |             return ("OK", attributes) | 
					
						
							|  |  |  |         if not hasattr(obj, methodname): | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |             return ("ERROR", "Unsupported method name: %r" % (methodname,)) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         method = getattr(obj, methodname) | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             if how == 'CALL': | 
					
						
							|  |  |  |                 ret = method(*args, **kwargs) | 
					
						
							|  |  |  |                 if isinstance(ret, RemoteObject): | 
					
						
							|  |  |  |                     ret = remoteref(ret) | 
					
						
							|  |  |  |                 return ("OK", ret) | 
					
						
							|  |  |  |             elif how == 'QUEUE': | 
					
						
							|  |  |  |                 request_queue.put((seq, (method, args, kwargs))) | 
					
						
							|  |  |  |                 return("QUEUED", None) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return ("ERROR", "Unsupported message type: %s" % how) | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |         except SystemExit: | 
					
						
							|  |  |  |             raise | 
					
						
							| 
									
										
										
										
											2003-03-10 20:42:24 +00:00
										 |  |  |         except socket.error: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             raise | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         except: | 
					
						
							| 
									
										
										
										
											2004-12-23 04:39:55 +00:00
										 |  |  |             msg = "*** Internal Error: rpc.py:SocketIO.localcall()\n\n"\ | 
					
						
							|  |  |  |                   " Object: %s \n Method: %s \n Args: %s\n" | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print(msg % (oid, method, args), file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2003-02-27 23:04:17 +00:00
										 |  |  |             traceback.print_exc(file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2003-01-31 05:06:43 +00:00
										 |  |  |             return ("EXCEPTION", None) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def remotecall(self, oid, methodname, args, kwargs): | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |         self.debug("remotecall:asynccall: ", oid, methodname) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         seq = self.asynccall(oid, methodname, args, kwargs) | 
					
						
							| 
									
										
										
										
											2002-12-06 21:45:24 +00:00
										 |  |  |         return self.asyncreturn(seq) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def remotequeue(self, oid, methodname, args, kwargs): | 
					
						
							|  |  |  |         self.debug("remotequeue:asyncqueue: ", oid, methodname) | 
					
						
							|  |  |  |         seq = self.asyncqueue(oid, methodname, args, kwargs) | 
					
						
							|  |  |  |         return self.asyncreturn(seq) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def asynccall(self, oid, methodname, args, kwargs): | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         request = ("CALL", (oid, methodname, args, kwargs)) | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         seq = self.newseq() | 
					
						
							| 
									
										
										
										
											2008-06-13 02:00:47 +00:00
										 |  |  |         if threading.current_thread() != self.sockthread: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             cvar = threading.Condition() | 
					
						
							|  |  |  |             self.cvars[seq] = cvar | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         self.debug(("asynccall:%d:" % seq), oid, methodname, args, kwargs) | 
					
						
							|  |  |  |         self.putmessage((seq, request)) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         return seq | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def asyncqueue(self, oid, methodname, args, kwargs): | 
					
						
							|  |  |  |         request = ("QUEUE", (oid, methodname, args, kwargs)) | 
					
						
							|  |  |  |         seq = self.newseq() | 
					
						
							| 
									
										
										
										
											2008-06-13 02:00:47 +00:00
										 |  |  |         if threading.current_thread() != self.sockthread: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             cvar = threading.Condition() | 
					
						
							|  |  |  |             self.cvars[seq] = cvar | 
					
						
							|  |  |  |         self.debug(("asyncqueue:%d:" % seq), oid, methodname, args, kwargs) | 
					
						
							|  |  |  |         self.putmessage((seq, request)) | 
					
						
							|  |  |  |         return seq | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def asyncreturn(self, seq): | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         self.debug("asyncreturn:%d:call getresponse(): " % seq) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         response = self.getresponse(seq, wait=0.05) | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         self.debug(("asyncreturn:%d:response: " % seq), response) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         return self.decoderesponse(response) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def decoderesponse(self, response): | 
					
						
							|  |  |  |         how, what = response | 
					
						
							|  |  |  |         if how == "OK": | 
					
						
							|  |  |  |             return what | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         if how == "QUEUED": | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         if how == "EXCEPTION": | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |             self.debug("decoderesponse: EXCEPTION") | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         if how == "EOF": | 
					
						
							|  |  |  |             self.debug("decoderesponse: EOF") | 
					
						
							|  |  |  |             self.decode_interrupthook() | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         if how == "ERROR": | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  |             self.debug("decoderesponse: Internal ERROR:", what) | 
					
						
							| 
									
										
										
										
											2007-08-23 01:06:15 +00:00
										 |  |  |             raise RuntimeError(what) | 
					
						
							|  |  |  |         raise SystemError(how, what) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def decode_interrupthook(self): | 
					
						
							|  |  |  |         "" | 
					
						
							|  |  |  |         raise EOFError | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def mainloop(self): | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         """Listen on socket until I/O not ready or EOF
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         pollresponse() will loop looking for seq number None, which | 
					
						
							| 
									
										
										
										
											2003-03-12 20:52:00 +00:00
										 |  |  |         never comes, and exit on EOFError. | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             self.getresponse(myseq=None, wait=0.05) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         except EOFError: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             self.debug("mainloop:return") | 
					
						
							|  |  |  |             return | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-12 20:52:00 +00:00
										 |  |  |     def getresponse(self, myseq, wait): | 
					
						
							|  |  |  |         response = self._getresponse(myseq, wait) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         if response is not None: | 
					
						
							|  |  |  |             how, what = response | 
					
						
							|  |  |  |             if how == "OK": | 
					
						
							|  |  |  |                 response = how, self._proxify(what) | 
					
						
							|  |  |  |         return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _proxify(self, obj): | 
					
						
							|  |  |  |         if isinstance(obj, RemoteProxy): | 
					
						
							|  |  |  |             return RPCProxy(self, obj.oid) | 
					
						
							| 
									
										
										
										
											2007-06-07 23:15:56 +00:00
										 |  |  |         if isinstance(obj, list): | 
					
						
							| 
									
										
										
										
											2007-08-09 18:00:23 +00:00
										 |  |  |             return list(map(self._proxify, obj)) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         # XXX Check for other types -- not currently needed | 
					
						
							|  |  |  |         return obj | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-03-12 20:52:00 +00:00
										 |  |  |     def _getresponse(self, myseq, wait): | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         self.debug("_getresponse:myseq:", myseq) | 
					
						
							| 
									
										
										
										
											2008-06-13 02:00:47 +00:00
										 |  |  |         if threading.current_thread() is self.sockthread: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # this thread does all reading of requests or responses | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             while 1: | 
					
						
							| 
									
										
										
										
											2003-03-12 20:52:00 +00:00
										 |  |  |                 response = self.pollresponse(myseq, wait) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 if response is not None: | 
					
						
							|  |  |  |                     return response | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # wait for notification from socket handling thread | 
					
						
							|  |  |  |             cvar = self.cvars[myseq] | 
					
						
							|  |  |  |             cvar.acquire() | 
					
						
							| 
									
										
										
										
											2006-08-22 15:45:46 +00:00
										 |  |  |             while myseq not in self.responses: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 cvar.wait() | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             response = self.responses[myseq] | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             self.debug("_getresponse:%s: thread woke up: response: %s" % | 
					
						
							|  |  |  |                        (myseq, response)) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             del self.responses[myseq] | 
					
						
							|  |  |  |             del self.cvars[myseq] | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             cvar.release() | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |             return response | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def newseq(self): | 
					
						
							|  |  |  |         self.nextseq = seq = self.nextseq + 2 | 
					
						
							|  |  |  |         return seq | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def putmessage(self, message): | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         self.debug("putmessage:%d:" % message[0]) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             s = pickle.dumps(message) | 
					
						
							| 
									
										
										
										
											2004-01-21 19:21:11 +00:00
										 |  |  |         except pickle.PicklingError: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("Cannot pickle:", repr(message), file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             raise | 
					
						
							|  |  |  |         s = struct.pack("<i", len(s)) + s | 
					
						
							|  |  |  |         while len(s) > 0: | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2004-01-21 19:21:11 +00:00
										 |  |  |                 r, w, x = select.select([], [self.sock], []) | 
					
						
							|  |  |  |                 n = self.sock.send(s[:BUFSIZE]) | 
					
						
							| 
									
										
										
										
											2005-05-10 03:44:24 +00:00
										 |  |  |             except (AttributeError, TypeError): | 
					
						
							| 
									
										
										
										
											2007-08-23 01:06:15 +00:00
										 |  |  |                 raise IOError("socket no longer exists") | 
					
						
							| 
									
										
										
										
											2005-05-10 03:44:24 +00:00
										 |  |  |             except socket.error: | 
					
						
							|  |  |  |                 raise | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 s = s[n:] | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-22 21:33:27 +00:00
										 |  |  |     buff = b'' | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     bufneed = 4 | 
					
						
							|  |  |  |     bufstate = 0 # meaning: 0 => reading count; 1 => reading data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def pollpacket(self, wait): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         self._stage0() | 
					
						
							| 
									
										
										
										
											2007-08-22 21:33:27 +00:00
										 |  |  |         if len(self.buff) < self.bufneed: | 
					
						
							| 
									
										
										
										
											2004-01-21 19:21:11 +00:00
										 |  |  |             r, w, x = select.select([self.sock.fileno()], [], [], wait) | 
					
						
							|  |  |  |             if len(r) == 0: | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 return None | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 s = self.sock.recv(BUFSIZE) | 
					
						
							|  |  |  |             except socket.error: | 
					
						
							|  |  |  |                 raise EOFError | 
					
						
							|  |  |  |             if len(s) == 0: | 
					
						
							|  |  |  |                 raise EOFError | 
					
						
							| 
									
										
										
										
											2007-08-22 21:33:27 +00:00
										 |  |  |             self.buff += s | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             self._stage0() | 
					
						
							|  |  |  |         return self._stage1() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _stage0(self): | 
					
						
							| 
									
										
										
										
											2007-08-22 21:33:27 +00:00
										 |  |  |         if self.bufstate == 0 and len(self.buff) >= 4: | 
					
						
							|  |  |  |             s = self.buff[:4] | 
					
						
							|  |  |  |             self.buff = self.buff[4:] | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             self.bufneed = struct.unpack("<i", s)[0] | 
					
						
							|  |  |  |             self.bufstate = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _stage1(self): | 
					
						
							| 
									
										
										
										
											2007-08-22 21:33:27 +00:00
										 |  |  |         if self.bufstate == 1 and len(self.buff) >= self.bufneed: | 
					
						
							|  |  |  |             packet = self.buff[:self.bufneed] | 
					
						
							|  |  |  |             self.buff = self.buff[self.bufneed:] | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             self.bufneed = 4 | 
					
						
							|  |  |  |             self.bufstate = 0 | 
					
						
							|  |  |  |             return packet | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def pollmessage(self, wait): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         packet = self.pollpacket(wait) | 
					
						
							|  |  |  |         if packet is None: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             message = pickle.loads(packet) | 
					
						
							| 
									
										
										
										
											2004-01-21 19:21:11 +00:00
										 |  |  |         except pickle.UnpicklingError: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("-----------------------", file=sys.__stderr__) | 
					
						
							|  |  |  |             print("cannot unpickle packet:", repr(packet), file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             traceback.print_stack(file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("-----------------------", file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             raise | 
					
						
							|  |  |  |         return message | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def pollresponse(self, myseq, wait): | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |         """Handle messages received on the socket.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         Some messages received may be asynchronous 'call' or 'queue' requests, | 
					
						
							|  |  |  |         and some may be responses for other threads. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         'call' requests are passed to self.localcall() with the expectation of | 
					
						
							|  |  |  |         immediate execution, during which time the socket is not serviced. | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |         'queue' requests are used for tasks (which may block or hang) to be | 
					
						
							|  |  |  |         processed in a different thread.  These requests are fed into | 
					
						
							|  |  |  |         request_queue by self.localcall().  Responses to queued requests are | 
					
						
							|  |  |  |         taken from response_queue and sent across the link with the associated | 
					
						
							|  |  |  |         sequence numbers.  Messages in the queues are (sequence_number, | 
					
						
							|  |  |  |         request/response) tuples and code using this module removing messages | 
					
						
							|  |  |  |         from the request_queue is responsible for returning the correct | 
					
						
							|  |  |  |         sequence number in the response_queue. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pollresponse() will loop until a response message with the myseq | 
					
						
							|  |  |  |         sequence number is received, and will save other responses in | 
					
						
							|  |  |  |         self.responses and notify the owning thread. | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         while 1: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # send queued response if there is one available | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 qmsg = response_queue.get(0) | 
					
						
							| 
									
										
										
										
											2008-05-11 19:59:59 +00:00
										 |  |  |             except queue.Empty: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 pass | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 seq, response = qmsg | 
					
						
							|  |  |  |                 message = (seq, ('OK', response)) | 
					
						
							|  |  |  |                 self.putmessage(message) | 
					
						
							|  |  |  |             # poll for message on link | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 message = self.pollmessage(wait) | 
					
						
							|  |  |  |                 if message is None:  # socket not ready | 
					
						
							|  |  |  |                     return None | 
					
						
							|  |  |  |             except EOFError: | 
					
						
							|  |  |  |                 self.handle_EOF() | 
					
						
							|  |  |  |                 return None | 
					
						
							|  |  |  |             except AttributeError: | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 return None | 
					
						
							|  |  |  |             seq, resq = message | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             how = resq[0] | 
					
						
							| 
									
										
										
										
											2003-01-25 03:26:35 +00:00
										 |  |  |             self.debug("pollresponse:%d:myseq:%s" % (seq, myseq)) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # process or queue a request | 
					
						
							|  |  |  |             if how in ("CALL", "QUEUE"): | 
					
						
							| 
									
										
										
										
											2003-01-25 21:33:40 +00:00
										 |  |  |                 self.debug("pollresponse:%d:localcall:call:" % seq) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 response = self.localcall(seq, resq) | 
					
						
							| 
									
										
										
										
											2003-01-25 21:33:40 +00:00
										 |  |  |                 self.debug("pollresponse:%d:localcall:response:%s" | 
					
						
							|  |  |  |                            % (seq, response)) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 if how == "CALL": | 
					
						
							|  |  |  |                     self.putmessage((seq, response)) | 
					
						
							|  |  |  |                 elif how == "QUEUE": | 
					
						
							|  |  |  |                     # don't acknowledge the 'queue' request! | 
					
						
							|  |  |  |                     pass | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # return if completed message transaction | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             elif seq == myseq: | 
					
						
							|  |  |  |                 return resq | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |             # must be a response for a different thread: | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 cv = self.cvars.get(seq, None) | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |                 # response involving unknown sequence number is discarded, | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                 # probably intended for prior incarnation of server | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 if cv is not None: | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                     cv.acquire() | 
					
						
							| 
									
										
										
										
											2003-02-17 18:57:16 +00:00
										 |  |  |                     self.responses[seq] = resq | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                     cv.notify() | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |                     cv.release() | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  |     def handle_EOF(self): | 
					
						
							|  |  |  |         "action taken upon link being closed by peer" | 
					
						
							|  |  |  |         self.EOFhook() | 
					
						
							|  |  |  |         self.debug("handle_EOF") | 
					
						
							|  |  |  |         for key in self.cvars: | 
					
						
							|  |  |  |             cv = self.cvars[key] | 
					
						
							|  |  |  |             cv.acquire() | 
					
						
							|  |  |  |             self.responses[key] = ('EOF', None) | 
					
						
							|  |  |  |             cv.notify() | 
					
						
							|  |  |  |             cv.release() | 
					
						
							|  |  |  |         # call our (possibly overridden) exit function | 
					
						
							|  |  |  |         self.exithook() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def EOFhook(self): | 
					
						
							|  |  |  |         "Classes using rpc client/server can override to augment EOF action" | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  | #----------------- end class SocketIO -------------------- | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  | class RemoteObject(object): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     # Token mix-in class | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def remoteref(obj): | 
					
						
							|  |  |  |     oid = id(obj) | 
					
						
							|  |  |  |     objecttable[oid] = obj | 
					
						
							|  |  |  |     return RemoteProxy(oid) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  | class RemoteProxy(object): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, oid): | 
					
						
							|  |  |  |         self.oid = oid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  | class RPCHandler(socketserver.BaseRequestHandler, SocketIO): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-06 21:45:24 +00:00
										 |  |  |     debugging = False | 
					
						
							|  |  |  |     location = "#S"  # Server | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, sock, addr, svr): | 
					
						
							|  |  |  |         svr.current_handler = self ## cgt xxx | 
					
						
							|  |  |  |         SocketIO.__init__(self, sock) | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  |         socketserver.BaseRequestHandler.__init__(self, sock, addr, svr) | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def handle(self): | 
					
						
							| 
									
										
										
										
											2008-05-12 02:31:37 +00:00
										 |  |  |         "handle() method required by socketserver" | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         self.mainloop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_remote_proxy(self, oid): | 
					
						
							|  |  |  |         return RPCProxy(self, oid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class RPCClient(SocketIO): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-06 21:45:24 +00:00
										 |  |  |     debugging = False | 
					
						
							|  |  |  |     location = "#C"  # Client | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |     nextseq = 1 # Requests coming from the client are odd numbered | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM): | 
					
						
							| 
									
										
										
										
											2002-08-25 14:08:07 +00:00
										 |  |  |         self.listening_sock = socket.socket(family, type) | 
					
						
							|  |  |  |         self.listening_sock.bind(address) | 
					
						
							|  |  |  |         self.listening_sock.listen(1) | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def accept(self): | 
					
						
							| 
									
										
										
										
											2002-08-25 14:08:07 +00:00
										 |  |  |         working_sock, address = self.listening_sock.accept() | 
					
						
							| 
									
										
										
										
											2002-12-23 22:51:03 +00:00
										 |  |  |         if self.debugging: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("****** Connection request from ", address, file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2003-06-05 23:51:29 +00:00
										 |  |  |         if address[0] == LOCALHOST: | 
					
						
							| 
									
										
										
										
											2002-08-25 14:08:07 +00:00
										 |  |  |             SocketIO.__init__(self, working_sock) | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("** Invalid host: ", address, file=sys.__stderr__) | 
					
						
							| 
									
										
										
										
											2002-07-26 00:06:42 +00:00
										 |  |  |             raise socket.error | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_remote_proxy(self, oid): | 
					
						
							|  |  |  |         return RPCProxy(self, oid) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  | class RPCProxy(object): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     __methods = None | 
					
						
							|  |  |  |     __attributes = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, sockio, oid): | 
					
						
							|  |  |  |         self.sockio = sockio | 
					
						
							|  |  |  |         self.oid = oid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							|  |  |  |         if self.__methods is None: | 
					
						
							|  |  |  |             self.__getmethods() | 
					
						
							|  |  |  |         if self.__methods.get(name): | 
					
						
							|  |  |  |             return MethodProxy(self.sockio, self.oid, name) | 
					
						
							|  |  |  |         if self.__attributes is None: | 
					
						
							|  |  |  |             self.__getattributes() | 
					
						
							| 
									
										
										
										
											2006-08-22 15:45:46 +00:00
										 |  |  |         if name in self.__attributes: | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  |             value = self.sockio.remotecall(self.oid, '__getattribute__', | 
					
						
							|  |  |  |                                            (name,), {}) | 
					
						
							|  |  |  |             return value | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2007-08-23 01:06:15 +00:00
										 |  |  |             raise AttributeError(name) | 
					
						
							| 
									
										
										
										
											2003-05-08 20:26:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |     def __getattributes(self): | 
					
						
							|  |  |  |         self.__attributes = self.sockio.remotecall(self.oid, | 
					
						
							|  |  |  |                                                 "__attributes__", (), {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getmethods(self): | 
					
						
							|  |  |  |         self.__methods = self.sockio.remotecall(self.oid, | 
					
						
							|  |  |  |                                                 "__methods__", (), {}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _getmethods(obj, methods): | 
					
						
							|  |  |  |     # Helper to get a list of methods from an object | 
					
						
							|  |  |  |     # Adds names to dictionary argument 'methods' | 
					
						
							|  |  |  |     for name in dir(obj): | 
					
						
							|  |  |  |         attr = getattr(obj, name) | 
					
						
							| 
									
										
										
										
											2011-10-28 14:45:05 +02:00
										 |  |  |         if callable(attr): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |             methods[name] = 1 | 
					
						
							| 
									
										
										
										
											2007-06-07 23:15:56 +00:00
										 |  |  |     if isinstance(obj, type): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  |         for super in obj.__bases__: | 
					
						
							|  |  |  |             _getmethods(super, methods) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _getattributes(obj, attributes): | 
					
						
							|  |  |  |     for name in dir(obj): | 
					
						
							|  |  |  |         attr = getattr(obj, name) | 
					
						
							| 
									
										
										
										
											2011-10-28 14:45:05 +02:00
										 |  |  |         if not callable(attr): | 
					
						
							| 
									
										
										
										
											2002-12-31 16:03:23 +00:00
										 |  |  |             attributes[name] = 1 | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-21 22:10:32 +00:00
										 |  |  | class MethodProxy(object): | 
					
						
							| 
									
										
										
										
											2002-05-26 13:36:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, sockio, oid, name): | 
					
						
							|  |  |  |         self.sockio = sockio | 
					
						
							|  |  |  |         self.oid = oid | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, *args, **kwargs): | 
					
						
							|  |  |  |         value = self.sockio.remotecall(self.oid, self.name, args, kwargs) | 
					
						
							|  |  |  |         return value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-09-10 02:42:18 +00:00
										 |  |  | # XXX KBK 09Sep03  We need a proper unit test for this module.  Previously | 
					
						
							| 
									
										
											  
											
												Merged revisions 74277,74321,74323,74326,74355,74465,74467,74488,74492,74513,74531,74549,74553,74625,74632,74643-74644,74647,74652,74666,74671,74727,74739 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
  r74277 | sean.reifschneider | 2009-08-01 18:54:55 -0500 (Sat, 01 Aug 2009) | 3 lines
  - Issue #6624: yArg_ParseTuple with "s" format when parsing argument with
    NUL: Bogus TypeError detail string.
........
  r74321 | guilherme.polo | 2009-08-05 11:51:41 -0500 (Wed, 05 Aug 2009) | 1 line
  Easier reference to find (at least while svn continues being used).
........
  r74323 | guilherme.polo | 2009-08-05 18:48:26 -0500 (Wed, 05 Aug 2009) | 1 line
  Typo.
........
  r74326 | jesse.noller | 2009-08-05 21:05:56 -0500 (Wed, 05 Aug 2009) | 1 line
  Fix issue 4660: spurious task_done errors in multiprocessing, remove doc note for from_address
........
  r74355 | gregory.p.smith | 2009-08-12 12:02:37 -0500 (Wed, 12 Aug 2009) | 2 lines
  comment typo fix
........
  r74465 | vinay.sajip | 2009-08-15 18:23:12 -0500 (Sat, 15 Aug 2009) | 1 line
  Added section on logging to one file from multiple processes.
........
  r74467 | vinay.sajip | 2009-08-15 18:34:47 -0500 (Sat, 15 Aug 2009) | 1 line
  Refined section on logging to one file from multiple processes.
........
  r74488 | vinay.sajip | 2009-08-17 08:14:37 -0500 (Mon, 17 Aug 2009) | 1 line
  Further refined section on logging to one file from multiple processes.
........
  r74492 | r.david.murray | 2009-08-17 14:26:49 -0500 (Mon, 17 Aug 2009) | 2 lines
  Issue 6685: 'toupper' -> 'upper' in cgi doc example explanation.
........
  r74513 | skip.montanaro | 2009-08-18 09:37:52 -0500 (Tue, 18 Aug 2009) | 1 line
  missing module ref (issue6723)
........
  r74531 | vinay.sajip | 2009-08-20 17:04:32 -0500 (Thu, 20 Aug 2009) | 1 line
  Added section on exceptions raised during logging.
........
  r74549 | benjamin.peterson | 2009-08-24 12:42:36 -0500 (Mon, 24 Aug 2009) | 1 line
  fix pdf building by teaching latex the right encoding package
........
  r74553 | r.david.murray | 2009-08-26 20:04:59 -0500 (Wed, 26 Aug 2009) | 2 lines
  Remove leftover text from end of sentence.
........
  r74625 | benjamin.peterson | 2009-09-01 17:27:57 -0500 (Tue, 01 Sep 2009) | 1 line
  remove the check that classmethod's argument is a callable
........
  r74632 | georg.brandl | 2009-09-03 02:27:26 -0500 (Thu, 03 Sep 2009) | 1 line
  #6828: fix wrongly highlighted blocks.
........
  r74643 | georg.brandl | 2009-09-04 01:59:20 -0500 (Fri, 04 Sep 2009) | 2 lines
  Issue #2666: Handle BROWSER environment variable properly for unknown browser names in the webbrowser module.
........
  r74644 | georg.brandl | 2009-09-04 02:55:14 -0500 (Fri, 04 Sep 2009) | 1 line
  #5047: remove Monterey support from configure.
........
  r74647 | georg.brandl | 2009-09-04 03:17:04 -0500 (Fri, 04 Sep 2009) | 2 lines
  Issue #5275: In Cookie's Cookie.load(), properly handle non-string arguments as documented.
........
  r74652 | georg.brandl | 2009-09-04 06:25:37 -0500 (Fri, 04 Sep 2009) | 1 line
  #6756: add some info about the "acct" parameter.
........
  r74666 | georg.brandl | 2009-09-05 04:04:09 -0500 (Sat, 05 Sep 2009) | 1 line
  #6841: remove duplicated word.
........
  r74671 | georg.brandl | 2009-09-05 11:47:17 -0500 (Sat, 05 Sep 2009) | 1 line
  #6843: add link from filterwarnings to where the meaning of the arguments is covered.
........
  r74727 | benjamin.peterson | 2009-09-08 18:04:22 -0500 (Tue, 08 Sep 2009) | 1 line
  #6865 fix ref counting in initialization of pwd module
........
  r74739 | georg.brandl | 2009-09-11 02:55:20 -0500 (Fri, 11 Sep 2009) | 1 line
  Move function back to its section.
........
											
										 
											2009-09-11 22:24:02 +00:00
										 |  |  | #                  existing test code was removed at Rev 1.27 (r34098). |