/Demo/pdist/client.py

http://unladen-swallow.googlecode.com/ · Python · 157 lines · 149 code · 6 blank · 2 comment · 1 complexity · 15c4b048c5f383364fad94f8e6525300 MD5 · raw file

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