summaryrefslogtreecommitdiffstats
path: root/Demo/pdist/client.py
blob: a00f005bbceb1e815272081014f03478a534ba68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"""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 = repr(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)