"""RPC Server module.""" import sys import socket import pickle from fnmatch import fnmatch from repr import repr # Default verbosity (0 = silent, 1 = print connections, 2 = print requests too) VERBOSE = 1 class Server: """RPC Server class. Derive a class to implement a particular service.""" def __init__(self, address, verbose = VERBOSE): if type(address) == type(0): address = ('', address) self._address = address self._verbose = verbose self._socket = None self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.bind(address) self._socket.listen(1) self._listening = 1 def _setverbose(self, verbose): self._verbose = verbose def __del__(self): self._close() def _close(self): self._listening = 0 if self._socket: self._socket.close() self._socket = None def _serverloop(self): while self._listening: self._serve() def _serve(self): if self._verbose: print("Wait for connection ...") conn, address = self._socket.accept() if self._verbose: print("Accepted connection from %s" % repr(address)) if not self._verify(conn, address): print("*** Connection from %s refused" % repr(address)) conn.close() return rf = conn.makefile('r') wf = conn.makefile('w') ok = 1 while ok: wf.flush() if self._verbose > 1: print("Wait for next request ...") ok = self._dorequest(rf, wf) _valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*'] def _verify(self, conn, address): host, port = address for pat in self._valid: if fnmatch(host, pat): return 1 return 0 def _dorequest(self, rf, wf): rp = pickle.Unpickler(rf) try: request = rp.load() except EOFError: return 0 if self._verbose > 1: print("Got request: %s" % repr(request)) try: methodname, args, id = request if '.' in methodname: reply = (None, self._special(methodname, args), id) elif methodname[0] == '_': raise NameError("illegal method name %s" % repr(methodname)) else: method = getattr(self, methodname) reply = (None, method(*args), id) except: reply = (sys.exc_info()[:2], id) if id < 0 and reply[:2] == (None, None): if self._verbose > 1: print("Suppress reply") return 1 if self._verbose > 1: print("Send reply: %s" % repr(reply)) wp = pickle.Pickler(wf) wp.dump(reply) return 1 def _special(self, methodname, args): if methodname == '.methods': if not hasattr(self, '_methods'): self._methods = tuple(self._listmethods()) return self._methods raise NameError("unrecognized special method name %s" % repr(methodname)) def _listmethods(self, cl=None): if not cl: cl = self.__class__ names = list(cl.__dict__.keys()) names = [x for x in names if x[0] != '_'] names.sort() for base in cl.__bases__: basenames = self._listmethods(base) basenames = list(filter(lambda x, names=names: x not in names, basenames)) names[len(names):] = basenames return names from security import Security class SecureServer(Server, Security): def __init__(self, *args): Server.__init__(self, *args) Security.__init__(self) def _verify(self, conn, address): import string challenge = self._generate_challenge() conn.send("%d\n" % challenge) response = "" while "\n" not in response and len(response) < 100: data = conn.recv(100) if not data: break response = response + data try: response = string.atol(string.strip(response)) except string.atol_error: if self._verbose > 0: print("Invalid response syntax", repr(response)) return 0 if not self._compare_challenge_response(challenge, response): if self._verbose > 0: print("Invalid response value", repr(response)) return 0 if self._verbose > 1: print("Response matches challenge. Go ahead!") return 1