annotate rpc.py @ 27:e2833d081413

- Handle zero length data from the instrument. - Handle trailing newlines. - Add helper function to allow URL like instrument connections.
author Daniel O'Connor <darius@dons.net.au>
date Wed, 21 Sep 2011 14:56:21 +0930
parents cba1c44060f5
children 91b476ebc0f2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 "A an RPC module, with optimizations for VXI-11 rpc calls"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2 _rcsid="$Id: rpc.py 323 2011-04-06 19:10:03Z marcus $"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 #this module is 99% from the python distribution, Demo/rpc/rpc.py, with a few modifications
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 #by Marcus Mendenhall to improve timeout handling, etc. It probably should follow any licensing
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 #intent of whoever originated it.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 # Sun RPC version 2 -- RFC1057.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 # XXX There should be separate exceptions for the various reasons why
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 # XXX an RPC can fail, rather than using RuntimeError for everything
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 # XXX The UDP version of the protocol resends requests when it does
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 # XXX not receive a timely reply -- use only for idempotent calls!
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 # XXX There is no provision for call timeout on TCP connections
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 # Now there is, on receives. 2003.02.20 Marcus Mendenhall, Vanderbilt University marcus.h.mendenhall@vanderbilt.edu
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 import xdrlib as xdr
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 import socket
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 import os
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 from exceptions import *
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 RPCVERSION = 2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 CALL = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 REPLY = 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 AUTH_NULL = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 AUTH_UNIX = 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 AUTH_SHORT = 2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 AUTH_DES = 3
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34 MSG_ACCEPTED = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 MSG_DENIED = 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 SUCCESS = 0 # RPC executed successfully
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 PROG_UNAVAIL = 1 # remote hasn't exported program
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 PROG_MISMATCH = 2 # remote can't support version #
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40 PROC_UNAVAIL = 3 # program can't support procedure
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 GARBAGE_ARGS = 4 # procedure can't decode params
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43 RPC_MISMATCH = 0 # RPC version number != 2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 AUTH_ERROR = 1 # remote can't authenticate caller
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46 AUTH_BADCRED = 1 # bad credentials (seal broken)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 AUTH_REJECTEDCRED = 2 # client must begin new session
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 AUTH_BADVERF = 3 # bad verifier (seal broken)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 AUTH_REJECTEDVERF = 4 # verifier expired or replayed
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 AUTH_TOOWEAK = 5 # rejected for security reasons
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 class Packer(xdr.Packer):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 def pack_auth(self, auth):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56 flavor, stuff = auth
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 self.pack_enum(flavor)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58 self.pack_opaque(stuff)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 def pack_auth_unix(self, stamp, machinename, uid, gid, gids):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 self.pack_uint(stamp)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62 self.pack_string(machinename)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 self.pack_uint(uid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 self.pack_uint(gid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 self.pack_uint(len(gids))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 for i in gids:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 self.pack_uint(i)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 def pack_callheader(self, xid, prog, vers, proc, cred, verf):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 self.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 self.pack_enum(CALL)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 self.pack_uint(RPCVERSION)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 self.pack_uint(prog)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74 self.pack_uint(vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 self.pack_uint(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 self.pack_auth(cred)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 self.pack_auth(verf)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78 # Caller must add procedure-specific part of call
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 def pack_replyheader(self, xid, verf):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81 self.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 self.pack_enum(REPLY)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 self.pack_uint(MSG_ACCEPTED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 self.pack_auth(verf)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 self.pack_enum(SUCCESS)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86 # Caller must add procedure-specific part of reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 # Exceptions
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 BadRPCFormat = 'rpc.BadRPCFormat'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 BadRPCVersion = 'rpc.BadRPCVersion'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 GarbageArgs = 'rpc.GarbageArgs'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 class Unpacker(xdr.Unpacker):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96 def unpack_auth(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 flavor = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 stuff = self.unpack_opaque()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99 return (flavor, stuff)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 def unpack_callheader(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 xid = self.unpack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 temp = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 if temp <> CALL:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105 raise BadRPCFormat, 'no CALL but ' + `temp`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106 temp = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 if temp <> RPCVERSION:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 raise BadRPCVerspion, 'bad RPC version ' + `temp`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 prog = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110 vers = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 proc = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 cred = self.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 verf = self.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 return xid, prog, vers, proc, cred, verf
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 # Caller must add procedure-specific part of call
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 def unpack_replyheader(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118 xid = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 mtype = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 if mtype <> REPLY:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 raise RuntimeError, 'no REPLY but ' + `mtype`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 stat = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 if stat == MSG_DENIED:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124 stat = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125 if stat == RPC_MISMATCH:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 low = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 high = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128 raise RuntimeError, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 'MSG_DENIED: RPC_MISMATCH: ' + `low, high`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 if stat == AUTH_ERROR:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 stat = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 raise RuntimeError, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133 'MSG_DENIED: AUTH_ERROR: ' + `stat`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134 raise RuntimeError, 'MSG_DENIED: ' + `stat`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 if stat <> MSG_ACCEPTED:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136 raise RuntimeError, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 'Neither MSG_DENIED nor MSG_ACCEPTED: ' + `stat`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138 verf = self.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139 stat = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 if stat == PROG_UNAVAIL:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 raise RuntimeError, 'call failed: PROG_UNAVAIL'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
142 if stat == PROG_MISMATCH:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 low = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 high = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 raise RuntimeError, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
146 'call failed: PROG_MISMATCH: ' + `low, high`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147 if stat == PROC_UNAVAIL:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
148 raise RuntimeError, 'call failed: PROC_UNAVAIL'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 if stat == GARBAGE_ARGS:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150 raise RuntimeError, 'call failed: GARBAGE_ARGS'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151 if stat <> SUCCESS:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152 raise RuntimeError, 'call failed: ' + `stat`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153 return xid, verf
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154 # Caller must get procedure-specific part of reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157 # Subroutines to create opaque authentication objects
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159 def make_auth_null():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 return ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162 def make_auth_unix(seed, host, uid, gid, groups):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163 p = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164 p.pack_auth_unix(seed, host, uid, gid, groups)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165 return p.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167 def make_auth_unix_default():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
168 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
169 from os import getuid, getgid
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
170 uid = getuid()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
171 gid = getgid()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
172 except ImportError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
173 uid = gid = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
174 import time
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
175 return make_auth_unix(int(time.time()-unix_epoch()), \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
176 socket.gethostname(), uid, gid, [])
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
177
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
178 _unix_epoch = -1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
179 def unix_epoch():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
180 """Very painful calculation of when the Unix Epoch is.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
181
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
182 This is defined as the return value of time.time() on Jan 1st,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
183 1970, 00:00:00 GMT.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
184
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
185 On a Unix system, this should always return 0.0. On a Mac, the
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
186 calculations are needed -- and hard because of integer overflow
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
187 and other limitations.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
188
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
189 """
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
190 global _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
191 if _unix_epoch >= 0: return _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
192 import time
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
193 now = time.time()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
194 localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
195 gmt = time.gmtime(now)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
196 offset = time.mktime(localt) - time.mktime(gmt)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
197 y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
198 offset, ss = divmod(ss + offset, 60)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
199 offset, mm = divmod(mm + offset, 60)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
200 offset, hh = divmod(hh + offset, 24)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
201 d = d + offset
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
202 _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
203 print "Unix epoch:", time.ctime(_unix_epoch)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
204 return _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
205
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
206
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
207 # Common base class for clients
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
208
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
209 class Client:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
210
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
211 def __init__(self, host, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
212 self.host = host
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
213 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
214 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
215 self.port = port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
216 self.makesocket() # Assigns to self.sock
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
217 self.bindsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
218 self.connsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
219 self.lastxid = 0 # XXX should be more random?
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
220 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
221 self.cred = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
222 self.verf = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
223
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
224 def close(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
225 self.sock.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
226
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
227 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
228 # This MUST be overridden
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
229 raise RuntimeError, 'makesocket not defined'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
230
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
231 def connsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
232 # Override this if you don't want/need a connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
233 self.sock.connect((self.host, self.port))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
234
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
235 def bindsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
236 # Override this to bind to a different port (e.g. reserved)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
237 self.sock.bind(('', 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
238
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
239 def addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
240 # Override this to use derived classes from Packer/Unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
241 self.packer = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
242 self.unpacker = Unpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
243
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
244 def make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
245 #print "make_call() args = " + str(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
246 # Don't normally override this (but see Broadcast)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
247 if pack_func is None and args is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
248 raise TypeError, 'non-null args with null pack_func'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
249 #print "packed args"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
250 self.start_call(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
251 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
252 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
253 self.do_call()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
254 if unpack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
255 result = unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
256 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
257 result = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
258 #print "result = " + str(result)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
259 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
260 return result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
261
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
262 def start_call(self, proc):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
263 # Don't override this
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
264 self.lastxid = xid = self.lastxid + 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
265 cred = self.mkcred()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
266 verf = self.mkverf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
267 p = self.packer
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
268 p.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
269 p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
270
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
271 def do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
272 # This MUST be overridden
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
273 raise RuntimeError, 'do_call not defined'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
274
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
275 def mkcred(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
276 # Override this to use more powerful credentials
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
277 if self.cred == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
278 self.cred = (AUTH_NULL, make_auth_null())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
279 return self.cred
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
280
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
281 def mkverf(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
282 # Override this to use a more powerful verifier
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
283 if self.verf == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
284 self.verf = (AUTH_NULL, make_auth_null())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
285 return self.verf
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
286
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
287 def call_0(self): # Procedure 0 is always like this
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
288 return self.make_call(0, None, None, None)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
289
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
290
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
291 # Record-Marking standard support
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
292
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
293 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
294 from select import select as _select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
295 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
296 _select=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
297
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
298 def sendfrag_with_timeout(sock, last, frag, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
299 x = len(frag)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
300 if last: x = x | 0x80000000L
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
301 header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
302 chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
303 block=header+frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
304 n=len(block)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
305 nsent=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
306 while(nsent<n):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
307 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
308 rlist, wlist, xlist=_select([],[sock],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
309 if not wlist:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
310 raise EOFError, "Blocked write in sendfrag()"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
311 nsent+=sock.send(block[nsent:])
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
312
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
313 def recvfrag_with_timeout(sock, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
314 #print "receiving from ", sock
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
315 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
316 #print "Selecting with timeout...", timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
317 rlist, wlist, xlist=_select([sock],[],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
318 if not rlist:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
319 raise EOFError, "No header at all in recvfrag()"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
320
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
321 header = sock.recv(4)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
322 if len(header) < 4:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
323 raise EOFError
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
324 x = long(ord(header[0]))<<24 | ord(header[1])<<16 | \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
325 ord(header[2])<<8 | ord(header[3])
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
326 last = ((x & 0x80000000L) != 0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
327 n = int(x & 0x7fffffff)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
328
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
329 frag=''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
330
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
331 while(len(frag) < n):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
332 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
333 #print "Selecting with timeout...", timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
334 rlist, wlist, xlist=_select([sock],[],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
335 if not rlist:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
336 raise EOFError, "No data after header in recvfrag()"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
337 frag += sock.recv(n-len(frag))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
338
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
339 return last, frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
340
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
341
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
342 def recvrecord(sock, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
343 record = ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
344 last = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
345 while not last:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
346 last, frag = recvfrag_with_timeout(sock, timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
347 record = record + frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
348 return record
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
349
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
350 def sendrecord(sock, record, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
351 sendfrag_with_timeout(sock, 1, record, timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
352
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
353
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
354
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
355 # Try to bind to a reserved port (must be root)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
356
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
357 last_resv_port_tried = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
358 def bindresvport(sock, host):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
359 global last_resv_port_tried
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
360 FIRST, LAST = 600, 1024 # Range of ports to try
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
361 if last_resv_port_tried == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
362 import os
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
363 last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
364 for i in range(last_resv_port_tried, LAST) + \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
365 range(FIRST, last_resv_port_tried):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
366 last_resv_port_tried = i
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
367 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
368 sock.bind((host, i))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
369 return last_resv_port_tried
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
370 except socket.error, (errno, msg):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
371 if errno <> 114:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
372 raise socket.error, (errno, msg)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
373 raise RuntimeError, 'can\'t assign reserved port'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
374
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
375
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
376 # Client using TCP to a specific port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
377
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
378 class RawTCPClient(Client):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
379
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
380 select_timeout_seconds=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
381
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
382 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
383 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
384
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
385 def do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
386 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
387 sendrecord(self.sock, call, self.select_timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
388 reply = recvrecord(self.sock, self.select_timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
389 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
390 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
391 xid, verf = u.unpack_replyheader()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
392 if xid <> self.lastxid:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
393 # Can't really happen since this is TCP...
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
394 raise RuntimeError, 'wrong xid in reply ' + `xid` + \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
395 ' instead of ' + `self.lastxid`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
396
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
397
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
398 # Client using UDP to a specific port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
399
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
400 class RawUDPClient(Client):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
401
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
402 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
403 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
404
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
405 def do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
406 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
407 self.sock.send(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
408 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
409 from select import select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
410 except ImportError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
411 print 'WARNING: select not found, RPC may hang'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
412 select = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
413 BUFSIZE = 8192 # Max UDP buffer size
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
414 timeout = 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
415 count = 5
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
416 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
417 r, w, x = [self.sock], [], []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
418 if select:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
419 r, w, x = select(r, w, x, timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
420 if self.sock not in r:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
421 count = count - 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
422 if count < 0: raise RuntimeError, 'timeout'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
423 if timeout < 25: timeout = timeout *2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
424 ## print 'RESEND', timeout, count
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
425 self.sock.send(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
426 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
427 reply = self.sock.recv(BUFSIZE)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
428 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
429 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
430 xid, verf = u.unpack_replyheader()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
431 if xid <> self.lastxid:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
432 ## print 'BAD xid'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
433 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
434 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
435
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
436
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
437 # Client using UDP broadcast to a specific port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
438
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
439 class RawBroadcastUDPClient(RawUDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
440
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
441 def __init__(self, bcastaddr, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
442 RawUDPClient.__init__(self, bcastaddr, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
443 self.reply_handler = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
444 self.timeout = 30
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
445
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
446 def connsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
447 # Don't connect -- use sendto
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
448 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
449
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
450 def set_reply_handler(self, reply_handler):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
451 self.reply_handler = reply_handler
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
452
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
453 def set_timeout(self, timeout):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
454 self.timeout = timeout # Use None for infinite timeout
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
455
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
456 def make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
457 if pack_func is None and args is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
458 raise TypeError, 'non-null args with null pack_func'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
459 self.start_call(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
460 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
461 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
462 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
463 self.sock.sendto(call, (self.host, self.port))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
464 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
465 from select import select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
466 except ImportError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
467 print 'WARNING: select not found, broadcast will hang'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
468 select = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
469 BUFSIZE = 8192 # Max UDP buffer size (for reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
470 replies = []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
471 if unpack_func is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
472 def dummy(): pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
473 unpack_func = dummy
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
474 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
475 r, w, x = [self.sock], [], []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
476 if select:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
477 if self.timeout is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
478 r, w, x = select(r, w, x)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
479 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
480 r, w, x = select(r, w, x, self.timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
481 if self.sock not in r:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
482 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
483 reply, fromaddr = self.sock.recvfrom(BUFSIZE)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
484 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
485 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
486 xid, verf = u.unpack_replyheader()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
487 if xid <> self.lastxid:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
488 ## print 'BAD xid'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
489 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
490 reply = unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
491 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
492 replies.append((reply, fromaddr))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
493 if self.reply_handler:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
494 self.reply_handler(reply, fromaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
495 return replies
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
496
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
497
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
498 # Port mapper interface
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
499
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
500 # Program number, version and (fixed!) port number
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
501 PMAP_PROG = 100000
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
502 PMAP_VERS = 2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
503 PMAP_PORT = 111
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
504
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
505 # Procedure numbers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
506 PMAPPROC_NULL = 0 # (void) -> void
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
507 PMAPPROC_SET = 1 # (mapping) -> bool
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
508 PMAPPROC_UNSET = 2 # (mapping) -> bool
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
509 PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
510 PMAPPROC_DUMP = 4 # (void) -> pmaplist
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
511 PMAPPROC_CALLIT = 5 # (call_args) -> call_result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
512
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
513 # A mapping is (prog, vers, prot, port) and prot is one of:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
514
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
515 IPPROTO_TCP = 6
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
516 IPPROTO_UDP = 17
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
517
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
518 # A pmaplist is a variable-length list of mappings, as follows:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
519 # either (1, mapping, pmaplist) or (0).
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
520
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
521 # A call_args is (prog, vers, proc, args) where args is opaque;
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
522 # a call_result is (port, res) where res is opaque.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
523
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
524
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
525 class PortMapperPacker(Packer):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
526
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
527 def pack_mapping(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
528 prog, vers, prot, port = mapping
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
529 self.pack_uint(prog)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
530 self.pack_uint(vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
531 self.pack_uint(prot)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
532 self.pack_uint(port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
533
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
534 def pack_pmaplist(self, list):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
535 self.pack_list(list, self.pack_mapping)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
536
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
537 def pack_call_args(self, ca):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
538 prog, vers, proc, args = ca
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
539 self.pack_uint(prog)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
540 self.pack_uint(vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
541 self.pack_uint(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
542 self.pack_opaque(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
543
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
544
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
545 class PortMapperUnpacker(Unpacker):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
546
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
547 def unpack_mapping(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
548 prog = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
549 vers = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
550 prot = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
551 port = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
552 return prog, vers, prot, port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
553
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
554 def unpack_pmaplist(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
555 return self.unpack_list(self.unpack_mapping)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
556
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
557 def unpack_call_result(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
558 port = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
559 res = self.unpack_opaque()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
560 return port, res
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
561
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
562
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
563 class PartialPortMapperClient:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
564
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
565 def addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
566 self.packer = PortMapperPacker()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
567 self.unpacker = PortMapperUnpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
568
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
569 def Set(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
570 return self.make_call(PMAPPROC_SET, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
571 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
572 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
573
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
574 def Unset(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
575 return self.make_call(PMAPPROC_UNSET, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
576 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
577 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
578
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
579 def Getport(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
580 return self.make_call(PMAPPROC_GETPORT, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
581 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
582 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
583
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
584 def Dump(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
585 return self.make_call(PMAPPROC_DUMP, None, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
586 None, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
587 self.unpacker.unpack_pmaplist)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
588
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
589 def Callit(self, ca):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
590 return self.make_call(PMAPPROC_CALLIT, ca, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
591 self.packer.pack_call_args, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
592 self.unpacker.unpack_call_result)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
593
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
594
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
595 class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
596
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
597 def __init__(self, host, port=PMAP_PORT, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
598 RawTCPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
599 host, PMAP_PROG, PMAP_VERS, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
600 self.select_timeout_seconds=timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
601
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
602
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
603 class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
604
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
605 def __init__(self, host, port=PMAP_PORT):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
606 RawUDPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
607 host, PMAP_PROG, PMAP_VERS, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
608
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
609 class BroadcastUDPPortMapperClient(PartialPortMapperClient, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
610 RawBroadcastUDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
611
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
612 def __init__(self, bcastaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
613 RawBroadcastUDPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
614 bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
615
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
616
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
617 # Generic clients that find their server through the Port mapper
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
618
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
619 class TCPClient(RawTCPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
620
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
621 def __init__(self, host, prog, vers, portmap_proxy_host=None, portmap_proxy_port=PMAP_PORT, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
622
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
623 self.select_timeout_seconds=timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
624 if portmap_proxy_host is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
625 portmap_proxy_host=host #use a proxy to get around firewalled portmappers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
626 pmap = TCPPortMapperClient(portmap_proxy_host, portmap_proxy_port,timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
627 port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
628 pmap.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
629 if port == 0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
630 raise RuntimeError, 'program not registered'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
631 RawTCPClient.__init__(self, host, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
632
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
633
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
634 class UDPClient(RawUDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
635
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
636 def __init__(self, host, prog, vers, portmap_proxy_host=None, portmap_proxy_port=PMAP_PORT):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
637 if portmap_proxy_host is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
638 portmap_proxy_host=host #use a proxy to get around firewalled portmappers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
639 pmap = UDPPortMapperClient(portmap_proxy_host, portmap_proxy_port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
640 port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
641 pmap.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
642 if port == 0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
643 raise RuntimeError, 'program not registered'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
644 RawUDPClient.__init__(self, host, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
645
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
646
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
647 class BroadcastUDPClient(Client):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
648
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
649 def __init__(self, bcastaddr, prog, vers):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
650 self.pmap = BroadcastUDPPortMapperClient(bcastaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
651 self.pmap.set_reply_handler(self.my_reply_handler)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
652 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
653 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
654 self.user_reply_handler = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
655 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
656
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
657 def close(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
658 self.pmap.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
659
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
660 def set_reply_handler(self, reply_handler):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
661 self.user_reply_handler = reply_handler
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
662
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
663 def set_timeout(self, timeout):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
664 self.pmap.set_timeout(timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
665
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
666 def my_reply_handler(self, reply, fromaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
667 port, res = reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
668 self.unpacker.reset(res)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
669 result = self.unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
670 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
671 self.replies.append((result, fromaddr))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
672 if self.user_reply_handler is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
673 self.user_reply_handler(result, fromaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
674
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
675 def make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
676 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
677 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
678 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
679 if unpack_func is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
680 def dummy(): pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
681 self.unpack_func = dummy
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
682 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
683 self.unpack_func = unpack_func
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
684 self.replies = []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
685 packed_args = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
686 dummy_replies = self.pmap.Callit( \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
687 (self.prog, self.vers, proc, packed_args))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
688 return self.replies
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
689
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
690
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
691 # Server classes
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
692
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
693 # These are not symmetric to the Client classes
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
694 # XXX No attempt is made to provide authorization hooks yet
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
695
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
696 class Server:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
697
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
698 def __init__(self, host, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
699 self.host = host # Should normally be '' for default interface
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
700 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
701 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
702 self.port = port # Should normally be 0 for random port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
703 self.makesocket() # Assigns to self.sock and self.prot
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
704 self.bindsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
705 self.host, self.port = self.sock.getsockname()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
706 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
707
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
708 def handle(self, call):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
709 # Don't use unpack_header but parse the header piecewise
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
710 # XXX I have no idea if I am using the right error responses!
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
711 self.unpacker.reset(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
712 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
713 xid = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
714 self.packer.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
715 temp = self.unpacker.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
716 if temp <> CALL:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
717 return None # Not worthy of a reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
718 self.packer.pack_uint(REPLY)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
719 temp = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
720 if temp <> RPCVERSION:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
721 self.packer.pack_uint(MSG_DENIED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
722 self.packer.pack_uint(RPC_MISMATCH)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
723 self.packer.pack_uint(RPCVERSION)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
724 self.packer.pack_uint(RPCVERSION)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
725 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
726 self.packer.pack_uint(MSG_ACCEPTED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
727 self.packer.pack_auth((AUTH_NULL, make_auth_null()))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
728 prog = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
729 if prog <> self.prog:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
730 self.packer.pack_uint(PROG_UNAVAIL)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
731 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
732 vers = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
733 if vers <> self.vers:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
734 self.packer.pack_uint(PROG_MISMATCH)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
735 self.packer.pack_uint(self.vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
736 self.packer.pack_uint(self.vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
737 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
738 proc = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
739 methname = 'handle_' + `proc`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
740 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
741 meth = getattr(self, methname)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
742 except AttributeError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
743 self.packer.pack_uint(PROC_UNAVAIL)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
744 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
745 cred = self.unpacker.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
746 verf = self.unpacker.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
747 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
748 meth() # Unpack args, call turn_around(), pack reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
749 except (EOFError, GarbageArgs):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
750 # Too few or too many arguments
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
751 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
752 self.packer.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
753 self.packer.pack_uint(REPLY)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
754 self.packer.pack_uint(MSG_ACCEPTED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
755 self.packer.pack_auth((AUTH_NULL, make_auth_null()))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
756 self.packer.pack_uint(GARBAGE_ARGS)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
757 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
758
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
759 def turn_around(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
760 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
761 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
762 except RuntimeError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
763 raise GarbageArgs
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
764 self.packer.pack_uint(SUCCESS)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
765
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
766 def handle_0(self): # Handle NULL message
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
767 self.turn_around()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
768
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
769 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
770 # This MUST be overridden
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
771 raise RuntimeError, 'makesocket not defined'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
772
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
773 def bindsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
774 # Override this to bind to a different port (e.g. reserved)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
775 self.sock.bind((self.host, self.port))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
776
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
777 def addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
778 # Override this to use derived classes from Packer/Unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
779 self.packer = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
780 self.unpacker = Unpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
781
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
782
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
783 class TCPServer(Server):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
784
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
785 def register(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
786 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
787 p = TCPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
788 if not p.Set(mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
789 raise RuntimeError, 'register failed'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
790
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
791 def unregister(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
792 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
793 p = TCPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
794 if not p.Unset(mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
795 raise RuntimeError, 'unregister failed'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
796
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
797 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
798 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
799 self.prot = IPPROTO_TCP
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
800
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
801 def loop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
802 self.sock.listen(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
803 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
804 self.session(self.sock.accept())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
805
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
806 def session(self, connection):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
807 sock, (host, port) = connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
808 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
809 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
810 call = recvrecord(sock)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
811 except EOFError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
812 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
813 except socket.error, msg:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
814 print 'socket error:', msg
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
815 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
816 reply = self.handle(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
817 if reply is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
818 sendrecord(sock, reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
819
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
820 def forkingloop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
821 # Like loop but uses forksession()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
822 self.sock.listen(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
823 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
824 self.forksession(self.sock.accept())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
825
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
826 def forksession(self, connection):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
827 # Like session but forks off a subprocess
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
828 import os
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
829 # Wait for deceased children
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
830 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
831 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
832 pid, sts = os.waitpid(0, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
833 except os.error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
834 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
835 pid = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
836 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
837 pid = os.fork()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
838 if pid: # Parent
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
839 connection[0].close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
840 return
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
841 # Child
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
842 self.session(connection)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
843 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
844 # Make sure we don't fall through in the parent
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
845 if pid == 0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
846 os._exit(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
847
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
848
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
849 class UDPServer(Server):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
850
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
851 def register(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
852 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
853 p = UDPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
854 if not p.Set(mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
855 raise RuntimeError, 'register failed'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
856
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
857 def unregister(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
858 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
859 p = UDPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
860 if not p.Unset(mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
861 raise RuntimeError, 'unregister failed'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
862
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
863 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
864 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
865 self.prot = IPPROTO_UDP
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
866
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
867 def loop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
868 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
869 self.session()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
870
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
871 def session(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
872 call, host_port = self.sock.recvfrom(8192)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
873 reply = self.handle(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
874 if reply <> None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
875 self.sock.sendto(reply, host_port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
876
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
877
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
878 # Simple test program -- dump local portmapper status
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
879
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
880 def test():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
881 pmap = UDPPortMapperClient('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
882 list = pmap.Dump()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
883 list.sort()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
884 for prog, vers, prot, port in list:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
885 print prog, vers,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
886 if prot == IPPROTO_TCP: print 'tcp',
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
887 elif prot == IPPROTO_UDP: print 'udp',
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
888 else: print prot,
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
889 print port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
890
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
891
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
892 # Test program for broadcast operation -- dump everybody's portmapper status
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
893
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
894 def testbcast():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
895 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
896 if sys.argv[1:]:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
897 bcastaddr = sys.argv[1]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
898 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
899 bcastaddr = '<broadcast>'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
900 def rh(reply, fromaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
901 host, port = fromaddr
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
902 print host + '\t' + `reply`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
903 pmap = BroadcastUDPPortMapperClient(bcastaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
904 pmap.set_reply_handler(rh)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
905 pmap.set_timeout(5)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
906 replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
907
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
908
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
909 # Test program for server, with corresponding client
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
910 # On machine A: python -c 'import rpc; rpc.testsvr()'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
911 # On machine B: python -c 'import rpc; rpc.testclt()' A
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
912 # (A may be == B)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
913
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
914 def testsvr():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
915 # Simple test class -- proc 1 doubles its string argument as reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
916 class S(UDPServer):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
917 def handle_1(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
918 arg = self.unpacker.unpack_string()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
919 self.turn_around()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
920 print 'RPC function 1 called, arg', `arg`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
921 self.packer.pack_string(arg + arg)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
922 #
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
923 s = S('', 0x20000000, 1, 0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
924 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
925 s.unregister()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
926 except RuntimeError, msg:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
927 print 'RuntimeError:', msg, '(ignored)'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
928 s.register()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
929 print 'Service started...'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
930 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
931 s.loop()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
932 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
933 s.unregister()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
934 print 'Service interrupted.'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
935
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
936
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
937 def testclt():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
938 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
939 if sys.argv[1:]: host = sys.argv[1]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
940 else: host = ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
941 # Client for above server
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
942 class C(UDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
943 def call_1(self, arg):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
944 return self.make_call(1, arg, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
945 self.packer.pack_string, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
946 self.unpacker.unpack_string)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
947 c = C(host, 0x20000000, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
948 print 'making call...'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
949 reply = c.call_1('hello, world, ')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
950 print 'call returned', `reply`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
951
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
952 def testclt2():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
953 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
954 host = '127.0.0.1'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
955 # Client for above server
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
956 class C(UDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
957 def call_1(self, arg):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
958 return self.make_call(1, arg, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
959 self.packer.pack_string, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
960 self.unpacker.unpack_string)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
961 c = C(host, 0x20000000, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
962 print 'making call...'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
963 reply = c.call_1('hello, world, ')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
964 print 'call returned', `reply`
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
965