| """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: | 
 | 	 | 
 | 	"""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() | 
 |  | 
 |  | 
 | from security import Security | 
 |  | 
 |  | 
 | class SecureClient(Client, Security): | 
 |  | 
 | 	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 = `long(response)` | 
 | 		if line[-1] in 'Ll': line = line[:-1] | 
 | 		self._wf.write(line + '\n') | 
 | 		self._wf.flush() | 
 | 		self._post_init() | 
 |  | 
 | class _stub: | 
 | 	 | 
 | 	"""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) | 
 |  |