1"""RPC Client module.""" 2 3import sys 4import socket 5import pickle 6import __builtin__ 7import os 8 9 10# Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) 11VERBOSE = 1 12 13 14class Client: 15 16 """RPC Client class. No need to derive a class -- it's fully generic.""" 17 18 def __init__(self, address, verbose = VERBOSE): 19 self._pre_init(address, verbose) 20 self._post_init() 21 22 def _pre_init(self, address, verbose = VERBOSE): 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') 36 37 def _post_init(self): 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 129from security import Security 130 131 132class SecureClient(Client, Security): 133 134 def __init__(self, *args): 135 import string 136 apply(self._pre_init, args) 137 Security.__init__(self) 138 self._wf.flush() 139 line = self._rf.readline() 140 challenge = string.atoi(string.strip(line)) 141 response = self._encode_challenge(challenge) 142 line = repr(long(response)) 143 if line[-1] in 'Ll': line = line[:-1] 144 self._wf.write(line + '\n') 145 self._wf.flush() 146 self._post_init() 147 148class _stub: 149 150 """Helper class for Client -- each instance serves as a method of the client.""" 151 152 def __init__(self, client, name): 153 self._client = client 154 self._name = name 155 156 def __call__(self, *args): 157 return self._client._vcall(self._name, args) 158