]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """RPC Server module."""\r |
2 | \r | |
3 | import sys\r | |
4 | import socket\r | |
5 | import pickle\r | |
6 | from fnmatch import fnmatch\r | |
7 | from repr import repr\r | |
8 | \r | |
9 | \r | |
10 | # Default verbosity (0 = silent, 1 = print connections, 2 = print requests too)\r | |
11 | VERBOSE = 1\r | |
12 | \r | |
13 | \r | |
14 | class Server:\r | |
15 | \r | |
16 | """RPC Server class. Derive a class to implement a particular service."""\r | |
17 | \r | |
18 | def __init__(self, address, verbose = VERBOSE):\r | |
19 | if type(address) == type(0):\r | |
20 | address = ('', address)\r | |
21 | self._address = address\r | |
22 | self._verbose = verbose\r | |
23 | self._socket = None\r | |
24 | self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\r | |
25 | self._socket.bind(address)\r | |
26 | self._socket.listen(1)\r | |
27 | self._listening = 1\r | |
28 | \r | |
29 | def _setverbose(self, verbose):\r | |
30 | self._verbose = verbose\r | |
31 | \r | |
32 | def __del__(self):\r | |
33 | self._close()\r | |
34 | \r | |
35 | def _close(self):\r | |
36 | self._listening = 0\r | |
37 | if self._socket:\r | |
38 | self._socket.close()\r | |
39 | self._socket = None\r | |
40 | \r | |
41 | def _serverloop(self):\r | |
42 | while self._listening:\r | |
43 | self._serve()\r | |
44 | \r | |
45 | def _serve(self):\r | |
46 | if self._verbose: print "Wait for connection ..."\r | |
47 | conn, address = self._socket.accept()\r | |
48 | if self._verbose: print "Accepted connection from %s" % repr(address)\r | |
49 | if not self._verify(conn, address):\r | |
50 | print "*** Connection from %s refused" % repr(address)\r | |
51 | conn.close()\r | |
52 | return\r | |
53 | rf = conn.makefile('r')\r | |
54 | wf = conn.makefile('w')\r | |
55 | ok = 1\r | |
56 | while ok:\r | |
57 | wf.flush()\r | |
58 | if self._verbose > 1: print "Wait for next request ..."\r | |
59 | ok = self._dorequest(rf, wf)\r | |
60 | \r | |
61 | _valid = ['192.16.201.*', '192.16.197.*', '132.151.1.*', '129.6.64.*']\r | |
62 | \r | |
63 | def _verify(self, conn, address):\r | |
64 | host, port = address\r | |
65 | for pat in self._valid:\r | |
66 | if fnmatch(host, pat): return 1\r | |
67 | return 0\r | |
68 | \r | |
69 | def _dorequest(self, rf, wf):\r | |
70 | rp = pickle.Unpickler(rf)\r | |
71 | try:\r | |
72 | request = rp.load()\r | |
73 | except EOFError:\r | |
74 | return 0\r | |
75 | if self._verbose > 1: print "Got request: %s" % repr(request)\r | |
76 | try:\r | |
77 | methodname, args, id = request\r | |
78 | if '.' in methodname:\r | |
79 | reply = (None, self._special(methodname, args), id)\r | |
80 | elif methodname[0] == '_':\r | |
81 | raise NameError, "illegal method name %s" % repr(methodname)\r | |
82 | else:\r | |
83 | method = getattr(self, methodname)\r | |
84 | reply = (None, apply(method, args), id)\r | |
85 | except:\r | |
86 | reply = (sys.exc_type, sys.exc_value, id)\r | |
87 | if id < 0 and reply[:2] == (None, None):\r | |
88 | if self._verbose > 1: print "Suppress reply"\r | |
89 | return 1\r | |
90 | if self._verbose > 1: print "Send reply: %s" % repr(reply)\r | |
91 | wp = pickle.Pickler(wf)\r | |
92 | wp.dump(reply)\r | |
93 | return 1\r | |
94 | \r | |
95 | def _special(self, methodname, args):\r | |
96 | if methodname == '.methods':\r | |
97 | if not hasattr(self, '_methods'):\r | |
98 | self._methods = tuple(self._listmethods())\r | |
99 | return self._methods\r | |
100 | raise NameError, "unrecognized special method name %s" % repr(methodname)\r | |
101 | \r | |
102 | def _listmethods(self, cl=None):\r | |
103 | if not cl: cl = self.__class__\r | |
104 | names = cl.__dict__.keys()\r | |
105 | names = filter(lambda x: x[0] != '_', names)\r | |
106 | names.sort()\r | |
107 | for base in cl.__bases__:\r | |
108 | basenames = self._listmethods(base)\r | |
109 | basenames = filter(lambda x, names=names: x not in names, basenames)\r | |
110 | names[len(names):] = basenames\r | |
111 | return names\r | |
112 | \r | |
113 | \r | |
114 | from security import Security\r | |
115 | \r | |
116 | \r | |
117 | class SecureServer(Server, Security):\r | |
118 | \r | |
119 | def __init__(self, *args):\r | |
120 | apply(Server.__init__, (self,) + args)\r | |
121 | Security.__init__(self)\r | |
122 | \r | |
123 | def _verify(self, conn, address):\r | |
124 | import string\r | |
125 | challenge = self._generate_challenge()\r | |
126 | conn.send("%d\n" % challenge)\r | |
127 | response = ""\r | |
128 | while "\n" not in response and len(response) < 100:\r | |
129 | data = conn.recv(100)\r | |
130 | if not data:\r | |
131 | break\r | |
132 | response = response + data\r | |
133 | try:\r | |
134 | response = string.atol(string.strip(response))\r | |
135 | except string.atol_error:\r | |
136 | if self._verbose > 0:\r | |
137 | print "Invalid response syntax", repr(response)\r | |
138 | return 0\r | |
139 | if not self._compare_challenge_response(challenge, response):\r | |
140 | if self._verbose > 0:\r | |
141 | print "Invalid response value", repr(response)\r | |
142 | return 0\r | |
143 | if self._verbose > 1:\r | |
144 | print "Response matches challenge. Go ahead!"\r | |
145 | return 1\r |