| Guido van Rossum | 07a272d | 1995-04-10 11:40:52 +0000 | [diff] [blame] | 1 | """RPC Client module.""" | 
 | 2 |  | 
 | 3 | import sys | 
 | 4 | import socket | 
 | 5 | import pickle | 
 | 6 | import __builtin__ | 
 | 7 | import os | 
 | 8 |  | 
 | 9 |  | 
 | 10 | # Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) | 
 | 11 | VERBOSE = 1 | 
 | 12 |  | 
 | 13 |  | 
 | 14 | class Client: | 
 | 15 | 	 | 
 | 16 | 	"""RPC Client class.  No need to derive a class -- it's fully generic.""" | 
 | 17 | 	 | 
 | 18 | 	def __init__(self, address, verbose = VERBOSE): | 
| Guido van Rossum | 541df3e | 1995-06-21 02:08:55 +0000 | [diff] [blame^] | 19 | 		self._pre_init(address, verbose) | 
 | 20 | 		self._post_init() | 
 | 21 | 	 | 
 | 22 | 	def _pre_init(self, address, verbose = VERBOSE): | 
| Guido van Rossum | 07a272d | 1995-04-10 11:40:52 +0000 | [diff] [blame] | 23 | 		if type(address) == type(0): | 
 | 24 | 			address = ('', address) | 
 | 25 | 		self._address = address | 
 | 26 | 		self._verbose = verbose | 
 | 27 | 		if self._verbose: print "Connecting to %s ..." % repr(address) | 
 | 28 | 		self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | 
 | 29 | 		self._socket.connect(address) | 
 | 30 | 		if self._verbose: print "Connected." | 
 | 31 | 		self._lastid = 0 # Last id for which a reply has been received | 
 | 32 | 		self._nextid = 1 # Id of next request | 
 | 33 | 		self._replies = {} # Unprocessed replies | 
 | 34 | 		self._rf = self._socket.makefile('r') | 
 | 35 | 		self._wf = self._socket.makefile('w') | 
| Guido van Rossum | 541df3e | 1995-06-21 02:08:55 +0000 | [diff] [blame^] | 36 | 	 | 
 | 37 | 	def _post_init(self): | 
| Guido van Rossum | 07a272d | 1995-04-10 11:40:52 +0000 | [diff] [blame] | 38 | 		self._methods = self._call('.methods') | 
 | 39 | 	 | 
 | 40 | 	def __del__(self): | 
 | 41 | 		self._close() | 
 | 42 | 	 | 
 | 43 | 	def _close(self): | 
 | 44 | 		if self._rf: self._rf.close() | 
 | 45 | 		self._rf = None | 
 | 46 | 		if self._wf: self._wf.close() | 
 | 47 | 		self._wf = None | 
 | 48 | 		if self._socket: self._socket.close() | 
 | 49 | 		self._socket = None | 
 | 50 | 	 | 
 | 51 | 	def __getattr__(self, name): | 
 | 52 | 		if name in self._methods: | 
 | 53 | 			method = _stub(self, name) | 
 | 54 | 			setattr(self, name, method) # XXX circular reference | 
 | 55 | 			return method | 
 | 56 | 		raise AttributeError, name | 
 | 57 | 	 | 
 | 58 | 	def _setverbose(self, verbose): | 
 | 59 | 		self._verbose = verbose | 
 | 60 | 	 | 
 | 61 | 	def _call(self, name, *args): | 
 | 62 | 		return self._vcall(name, args) | 
 | 63 | 	 | 
 | 64 | 	def _vcall(self, name, args): | 
 | 65 | 		return self._recv(self._vsend(name, args)) | 
 | 66 | 	 | 
 | 67 | 	def _send(self, name, *args): | 
 | 68 | 		return self._vsend(name, args) | 
 | 69 | 	 | 
 | 70 | 	def _send_noreply(self, name, *args): | 
 | 71 | 		return self._vsend(name, args, 0) | 
 | 72 | 	 | 
 | 73 | 	def _vsend_noreply(self, name, args): | 
 | 74 | 		return self._vsend(name, args, 0) | 
 | 75 | 	 | 
 | 76 | 	def _vsend(self, name, args, wantreply = 1): | 
 | 77 | 		id = self._nextid | 
 | 78 | 		self._nextid = id+1 | 
 | 79 | 		if not wantreply: id = -id | 
 | 80 | 		request = (name, args, id) | 
 | 81 | 		if self._verbose > 1: print "sending request: %s" % repr(request) | 
 | 82 | 		wp = pickle.Pickler(self._wf) | 
 | 83 | 		wp.dump(request) | 
 | 84 | 		return id | 
 | 85 | 	 | 
 | 86 | 	def _recv(self, id): | 
 | 87 | 		exception, value, rid = self._vrecv(id) | 
 | 88 | 		if rid != id: | 
 | 89 | 			raise RuntimeError, "request/reply id mismatch: %d/%d" % (id, rid) | 
 | 90 | 		if exception is None: | 
 | 91 | 			return value | 
 | 92 | 		x = exception | 
 | 93 | 		if hasattr(__builtin__, exception): | 
 | 94 | 			x = getattr(__builtin__, exception) | 
 | 95 | 		elif exception in ('posix.error', 'mac.error'): | 
 | 96 | 			x = os.error | 
 | 97 | 		if x == exception: | 
 | 98 | 			exception = x | 
 | 99 | 		raise exception, value		 | 
 | 100 | 	 | 
 | 101 | 	def _vrecv(self, id): | 
 | 102 | 		self._flush() | 
 | 103 | 		if self._replies.has_key(id): | 
 | 104 | 			if self._verbose > 1: print "retrieving previous reply, id = %d" % id | 
 | 105 | 			reply = self._replies[id] | 
 | 106 | 			del self._replies[id] | 
 | 107 | 			return reply | 
 | 108 | 		aid = abs(id) | 
 | 109 | 		while 1: | 
 | 110 | 			if self._verbose > 1: print "waiting for reply, id = %d" % id | 
 | 111 | 			rp = pickle.Unpickler(self._rf) | 
 | 112 | 			reply = rp.load() | 
 | 113 | 			del rp | 
 | 114 | 			if self._verbose > 1: print "got reply: %s" % repr(reply) | 
 | 115 | 			rid = reply[2] | 
 | 116 | 			arid = abs(rid) | 
 | 117 | 			if arid == aid: | 
 | 118 | 				if self._verbose > 1: print "got it" | 
 | 119 | 				return reply | 
 | 120 | 			self._replies[rid] = reply | 
 | 121 | 			if arid > aid: | 
 | 122 | 				if self._verbose > 1: print "got higher id, assume all ok" | 
 | 123 | 				return (None, None, id) | 
 | 124 | 	 | 
 | 125 | 	def _flush(self): | 
 | 126 | 		self._wf.flush() | 
 | 127 |  | 
 | 128 |  | 
| Guido van Rossum | 45babef | 1995-06-21 01:00:17 +0000 | [diff] [blame] | 129 | from security import Security | 
 | 130 |  | 
 | 131 |  | 
 | 132 | class SecureClient(Client, Security): | 
 | 133 |  | 
 | 134 | 	def __init__(self, *args): | 
 | 135 | 		import string | 
| Guido van Rossum | 541df3e | 1995-06-21 02:08:55 +0000 | [diff] [blame^] | 136 | 		apply(self._pre_init, args) | 
| Guido van Rossum | 45babef | 1995-06-21 01:00:17 +0000 | [diff] [blame] | 137 | 		Security.__init__(self) | 
 | 138 | 		line = self._rf.readline() | 
| Guido van Rossum | 541df3e | 1995-06-21 02:08:55 +0000 | [diff] [blame^] | 139 | 		challenge = string.atoi(string.strip(line)) | 
| Guido van Rossum | 45babef | 1995-06-21 01:00:17 +0000 | [diff] [blame] | 140 | 		response = self._encode_challenge(challenge) | 
 | 141 | 		line = `long(response)` | 
 | 142 | 		if line[-1] in 'Ll': line = line[:-1] | 
 | 143 | 		self._wf.write(line + '\n') | 
 | 144 | 		self._wf.flush() | 
| Guido van Rossum | 541df3e | 1995-06-21 02:08:55 +0000 | [diff] [blame^] | 145 | 		self._post_init() | 
| Guido van Rossum | 45babef | 1995-06-21 01:00:17 +0000 | [diff] [blame] | 146 |  | 
| Guido van Rossum | 07a272d | 1995-04-10 11:40:52 +0000 | [diff] [blame] | 147 | class _stub: | 
 | 148 | 	 | 
 | 149 | 	"""Helper class for Client -- each instance serves as a method of the client.""" | 
 | 150 | 	 | 
 | 151 | 	def __init__(self, client, name): | 
 | 152 | 		self._client = client | 
 | 153 | 		self._name = name | 
 | 154 | 	 | 
 | 155 | 	def __call__(self, *args): | 
 | 156 | 		return self._client._vcall(self._name, args) | 
 | 157 |  |