| 
									
										
										
										
											1995-04-10 11:40:52 +00:00
										 |  |  | """RPC Client module.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import socket | 
					
						
							|  |  |  | import pickle | 
					
						
							|  |  |  | import __builtin__ | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) | 
					
						
							|  |  |  | VERBOSE = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Client: | 
					
						
							| 
									
										
										
										
											2004-07-18 05:56:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """RPC Client class.  No need to derive a class -- it's fully generic.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, address, verbose = VERBOSE): | 
					
						
							|  |  |  |         self._pre_init(address, verbose) | 
					
						
							|  |  |  |         self._post_init() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _pre_init(self, address, verbose = VERBOSE): | 
					
						
							|  |  |  |         if type(address) == type(0): | 
					
						
							|  |  |  |             address = ('', address) | 
					
						
							|  |  |  |         self._address = address | 
					
						
							|  |  |  |         self._verbose = verbose | 
					
						
							|  |  |  |         if self._verbose: print "Connecting to %s ..." % repr(address) | 
					
						
							|  |  |  |         self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | 
					
						
							|  |  |  |         self._socket.connect(address) | 
					
						
							|  |  |  |         if self._verbose: print "Connected." | 
					
						
							|  |  |  |         self._lastid = 0 # Last id for which a reply has been received | 
					
						
							|  |  |  |         self._nextid = 1 # Id of next request | 
					
						
							|  |  |  |         self._replies = {} # Unprocessed replies | 
					
						
							|  |  |  |         self._rf = self._socket.makefile('r') | 
					
						
							|  |  |  |         self._wf = self._socket.makefile('w') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _post_init(self): | 
					
						
							|  |  |  |         self._methods = self._call('.methods') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __del__(self): | 
					
						
							|  |  |  |         self._close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _close(self): | 
					
						
							|  |  |  |         if self._rf: self._rf.close() | 
					
						
							|  |  |  |         self._rf = None | 
					
						
							|  |  |  |         if self._wf: self._wf.close() | 
					
						
							|  |  |  |         self._wf = None | 
					
						
							|  |  |  |         if self._socket: self._socket.close() | 
					
						
							|  |  |  |         self._socket = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							|  |  |  |         if name in self._methods: | 
					
						
							|  |  |  |             method = _stub(self, name) | 
					
						
							|  |  |  |             setattr(self, name, method) # XXX circular reference | 
					
						
							|  |  |  |             return method | 
					
						
							|  |  |  |         raise AttributeError, name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _setverbose(self, verbose): | 
					
						
							|  |  |  |         self._verbose = verbose | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _call(self, name, *args): | 
					
						
							|  |  |  |         return self._vcall(name, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _vcall(self, name, args): | 
					
						
							|  |  |  |         return self._recv(self._vsend(name, args)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _send(self, name, *args): | 
					
						
							|  |  |  |         return self._vsend(name, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _send_noreply(self, name, *args): | 
					
						
							|  |  |  |         return self._vsend(name, args, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _vsend_noreply(self, name, args): | 
					
						
							|  |  |  |         return self._vsend(name, args, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _vsend(self, name, args, wantreply = 1): | 
					
						
							|  |  |  |         id = self._nextid | 
					
						
							|  |  |  |         self._nextid = id+1 | 
					
						
							|  |  |  |         if not wantreply: id = -id | 
					
						
							|  |  |  |         request = (name, args, id) | 
					
						
							|  |  |  |         if self._verbose > 1: print "sending request: %s" % repr(request) | 
					
						
							|  |  |  |         wp = pickle.Pickler(self._wf) | 
					
						
							|  |  |  |         wp.dump(request) | 
					
						
							|  |  |  |         return id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _recv(self, id): | 
					
						
							|  |  |  |         exception, value, rid = self._vrecv(id) | 
					
						
							|  |  |  |         if rid != id: | 
					
						
							|  |  |  |             raise RuntimeError, "request/reply id mismatch: %d/%d" % (id, rid) | 
					
						
							|  |  |  |         if exception is None: | 
					
						
							|  |  |  |             return value | 
					
						
							|  |  |  |         x = exception | 
					
						
							|  |  |  |         if hasattr(__builtin__, exception): | 
					
						
							|  |  |  |             x = getattr(__builtin__, exception) | 
					
						
							|  |  |  |         elif exception in ('posix.error', 'mac.error'): | 
					
						
							|  |  |  |             x = os.error | 
					
						
							|  |  |  |         if x == exception: | 
					
						
							|  |  |  |             exception = x | 
					
						
							|  |  |  |         raise exception, value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _vrecv(self, id): | 
					
						
							|  |  |  |         self._flush() | 
					
						
							|  |  |  |         if self._replies.has_key(id): | 
					
						
							|  |  |  |             if self._verbose > 1: print "retrieving previous reply, id = %d" % id | 
					
						
							|  |  |  |             reply = self._replies[id] | 
					
						
							|  |  |  |             del self._replies[id] | 
					
						
							|  |  |  |             return reply | 
					
						
							|  |  |  |         aid = abs(id) | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             if self._verbose > 1: print "waiting for reply, id = %d" % id | 
					
						
							|  |  |  |             rp = pickle.Unpickler(self._rf) | 
					
						
							|  |  |  |             reply = rp.load() | 
					
						
							|  |  |  |             del rp | 
					
						
							|  |  |  |             if self._verbose > 1: print "got reply: %s" % repr(reply) | 
					
						
							|  |  |  |             rid = reply[2] | 
					
						
							|  |  |  |             arid = abs(rid) | 
					
						
							|  |  |  |             if arid == aid: | 
					
						
							|  |  |  |                 if self._verbose > 1: print "got it" | 
					
						
							|  |  |  |                 return reply | 
					
						
							|  |  |  |             self._replies[rid] = reply | 
					
						
							|  |  |  |             if arid > aid: | 
					
						
							|  |  |  |                 if self._verbose > 1: print "got higher id, assume all ok" | 
					
						
							|  |  |  |                 return (None, None, id) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _flush(self): | 
					
						
							|  |  |  |         self._wf.flush() | 
					
						
							| 
									
										
										
										
											1995-04-10 11:40:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-06-21 01:00:17 +00:00
										 |  |  | from security import Security | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SecureClient(Client, Security): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-18 05:56:09 +00:00
										 |  |  |     def __init__(self, *args): | 
					
						
							|  |  |  |         import string | 
					
						
							|  |  |  |         apply(self._pre_init, args) | 
					
						
							|  |  |  |         Security.__init__(self) | 
					
						
							|  |  |  |         self._wf.flush() | 
					
						
							|  |  |  |         line = self._rf.readline() | 
					
						
							|  |  |  |         challenge = string.atoi(string.strip(line)) | 
					
						
							|  |  |  |         response = self._encode_challenge(challenge) | 
					
						
							|  |  |  |         line = repr(long(response)) | 
					
						
							|  |  |  |         if line[-1] in 'Ll': line = line[:-1] | 
					
						
							|  |  |  |         self._wf.write(line + '\n') | 
					
						
							|  |  |  |         self._wf.flush() | 
					
						
							|  |  |  |         self._post_init() | 
					
						
							| 
									
										
										
										
											1995-06-21 01:00:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-04-10 11:40:52 +00:00
										 |  |  | class _stub: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-07-18 05:56:09 +00:00
										 |  |  |     """Helper class for Client -- each instance serves as a method of the client.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, client, name): | 
					
						
							|  |  |  |         self._client = client | 
					
						
							|  |  |  |         self._name = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, *args): | 
					
						
							|  |  |  |         return self._client._vcall(self._name, args) |