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