• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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