annotate rpc.py @ 85:60ad91b4c67c default tip

Add 'quick' option to use a faster sweep time with no averaging. Useful for testing the hardware is setup correctly without having to wait 3 minutes.
author Daniel O'Connor <doconnor@gsoft.com.au>
date Mon, 21 Oct 2024 14:12:50 +1030
parents 91b476ebc0f2
children
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()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
104 if temp != CALL:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
105 raise BadRPCFormat('no CALL but ' + repr(temp))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106 temp = self.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
107 if temp != RPCVERSION:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
108 raise BadRPCVerspion('bad RPC version ' + repr(temp))
19
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()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
120 if mtype != REPLY:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
121 raise RuntimeError('no REPLY but ' + repr(mtype))
19
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()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
128 raise RuntimeError('MSG_DENIED: RPC_MISMATCH: ' + repr((low, high)))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 if stat == AUTH_ERROR:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 stat = self.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
131 raise RuntimeError('MSG_DENIED: AUTH_ERROR: ' + repr(stat))
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
132 raise RuntimeError('MSG_DENIED: ' + repr(stat))
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
133 if stat != MSG_ACCEPTED:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
134 raise RuntimeError('Neither MSG_DENIED nor MSG_ACCEPTED: ' + repr(stat))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 verf = self.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136 stat = self.unpack_enum()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 if stat == PROG_UNAVAIL:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
138 raise RuntimeError('call failed: PROG_UNAVAIL')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
139 if stat == PROG_MISMATCH:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 low = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 high = self.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
142 raise RuntimeError('call failed: PROG_MISMATCH: ' + repr((low, high)))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
143 if stat == PROC_UNAVAIL:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
144 raise RuntimeError('call failed: PROC_UNAVAIL')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 if stat == GARBAGE_ARGS:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
146 raise RuntimeError('call failed: GARBAGE_ARGS')
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
147 if stat != SUCCESS:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
148 raise RuntimeError('call failed: ' + repr(stat))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 return xid, verf
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150 # Caller must get procedure-specific part of reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153 # Subroutines to create opaque authentication objects
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155 def make_auth_null():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156 return ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158 def make_auth_unix(seed, host, uid, gid, groups):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159 p = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 p.pack_auth_unix(seed, host, uid, gid, groups)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161 return p.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163 def make_auth_unix_default():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165 from os import getuid, getgid
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166 uid = getuid()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167 gid = getgid()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
168 except ImportError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
169 uid = gid = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
170 import time
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
171 return make_auth_unix(int(time.time()-unix_epoch()), \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
172 socket.gethostname(), uid, gid, [])
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
173
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
174 _unix_epoch = -1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
175 def unix_epoch():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
176 """Very painful calculation of when the Unix Epoch is.
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 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
179 1970, 00:00:00 GMT.
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
180
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
181 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
182 calculations are needed -- and hard because of integer overflow
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
183 and other limitations.
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 """
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
186 global _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
187 if _unix_epoch >= 0: return _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
188 import time
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
189 now = time.time()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
190 localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
191 gmt = time.gmtime(now)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
192 offset = time.mktime(localt) - time.mktime(gmt)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
193 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
194 offset, ss = divmod(ss + offset, 60)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
195 offset, mm = divmod(mm + offset, 60)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
196 offset, hh = divmod(hh + offset, 24)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
197 d = d + offset
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
198 _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0))
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
199 print("Unix epoch:", time.ctime(_unix_epoch))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
200 return _unix_epoch
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
201
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
202
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
203 # Common base class for clients
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
204
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
205 class Client:
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 def __init__(self, host, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
208 self.host = host
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
209 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
210 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
211 self.port = port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
212 self.makesocket() # Assigns to self.sock
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
213 self.bindsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
214 self.connsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
215 self.lastxid = 0 # XXX should be more random?
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
216 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
217 self.cred = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
218 self.verf = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
219
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
220 def close(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
221 self.sock.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
222
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
223 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
224 # This MUST be overridden
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
225 raise RuntimeError('makesocket not defined')
19
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 connsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
228 # Override this if you don't want/need a connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
229 self.sock.connect((self.host, self.port))
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 bindsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
232 # Override this to bind to a different port (e.g. reserved)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
233 self.sock.bind(('', 0))
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 addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
236 # Override this to use derived classes from Packer/Unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
237 self.packer = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
238 self.unpacker = Unpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
239
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
240 def make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
241 #print "make_call() args = " + str(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
242 # Don't normally override this (but see Broadcast)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
243 if pack_func is None and args is not None:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
244 raise TypeError('non-null args with null pack_func')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
245 #print "packed args"
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
246 self.start_call(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
247 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
248 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
249 self.do_call()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
250 if unpack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
251 result = unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
252 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
253 result = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
254 #print "result = " + str(result)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
255 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
256 return result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
257
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
258 def start_call(self, proc):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
259 # Don't override this
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
260 self.lastxid = xid = self.lastxid + 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
261 cred = self.mkcred()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
262 verf = self.mkverf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
263 p = self.packer
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
264 p.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
265 p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
266
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
267 def do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
268 # This MUST be overridden
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
269 raise RuntimeError('do_call not defined')
19
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 mkcred(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
272 # Override this to use more powerful credentials
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
273 if self.cred == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
274 self.cred = (AUTH_NULL, make_auth_null())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
275 return self.cred
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
276
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
277 def mkverf(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
278 # Override this to use a more powerful verifier
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
279 if self.verf == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
280 self.verf = (AUTH_NULL, make_auth_null())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
281 return self.verf
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
282
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
283 def call_0(self): # Procedure 0 is always like this
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
284 return self.make_call(0, None, None, None)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
285
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 # Record-Marking standard support
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
288
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
289 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
290 from select import select as _select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
291 except:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
292 _select=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
293
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
294 def sendfrag_with_timeout(sock, last, frag, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
295 x = len(frag)
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
296 if last: x = x | 0x80000000
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
297 header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
298 chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
299 block=header+frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
300 n=len(block)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
301 nsent=0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
302 while(nsent<n):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
303 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
304 rlist, wlist, xlist=_select([],[sock],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
305 if not wlist:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
306 raise EOFError("Blocked write in sendfrag()")
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
307 nsent+=sock.send(block[nsent:])
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
308
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
309 def recvfrag_with_timeout(sock, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
310 #print "receiving from ", sock
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
311 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
312 #print "Selecting with timeout...", timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
313 rlist, wlist, xlist=_select([sock],[],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
314 if not rlist:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
315 raise EOFError("No header at all in recvfrag()")
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
316
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
317 header = sock.recv(4)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
318 if len(header) < 4:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
319 raise EOFError
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
320 x = int(ord(header[0]))<<24 | ord(header[1])<<16 | \
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
321 ord(header[2])<<8 | ord(header[3])
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
322 last = ((x & 0x80000000) != 0)
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
323 n = int(x & 0x7fffffff)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
324
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
325 frag=''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
326
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
327 while(len(frag) < n):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
328 if _select and timeout_seconds:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
329 #print "Selecting with timeout...", timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
330 rlist, wlist, xlist=_select([sock],[],[], timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
331 if not rlist:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
332 raise EOFError("No data after header in recvfrag()")
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
333 frag += sock.recv(n-len(frag))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
334
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
335 return last, frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
336
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
337
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
338 def recvrecord(sock, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
339 record = ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
340 last = 0
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
341 while not last:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
342 last, frag = recvfrag_with_timeout(sock, timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
343 record = record + frag
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
344 return record
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
345
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
346 def sendrecord(sock, record, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
347 sendfrag_with_timeout(sock, 1, record, timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
348
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
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
351 # Try to bind to a reserved port (must be root)
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 last_resv_port_tried = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
354 def bindresvport(sock, host):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
355 global last_resv_port_tried
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
356 FIRST, LAST = 600, 1024 # Range of ports to try
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
357 if last_resv_port_tried == None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
358 import os
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
359 last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
360 for i in list(range(last_resv_port_tried, LAST)) + \
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
361 list(range(FIRST, last_resv_port_tried)):
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
362 last_resv_port_tried = i
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
363 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
364 sock.bind((host, i))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
365 return last_resv_port_tried
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
366 except socket.error as xxx_todo_changeme:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
367 (errno, msg) = xxx_todo_changeme.args
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
368 if errno != 114:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
369 raise socket.error(errno, msg)
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
370 raise RuntimeError('can\'t assign reserved port')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
371
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
372
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
373 # Client using TCP to a specific 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 class RawTCPClient(Client):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
376
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
377 select_timeout_seconds=None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
378
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
379 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
380 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
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 do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
383 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
384 sendrecord(self.sock, call, self.select_timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
385 reply = recvrecord(self.sock, self.select_timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
386 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
387 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
388 xid, verf = u.unpack_replyheader()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
389 if xid != self.lastxid:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
390 # Can't really happen since this is TCP...
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
391 raise RuntimeError('wrong xid in reply ' + repr(xid) + \
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
392 ' instead of ' + repr(self.lastxid))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
393
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
394
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
395 # Client using UDP to a specific port
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 class RawUDPClient(Client):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
398
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
399 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
400 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
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 do_call(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
403 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
404 self.sock.send(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
405 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
406 from select import select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
407 except ImportError:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
408 print('WARNING: select not found, RPC may hang')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
409 select = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
410 BUFSIZE = 8192 # Max UDP buffer size
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
411 timeout = 1
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
412 count = 5
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
413 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
414 r, w, x = [self.sock], [], []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
415 if select:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
416 r, w, x = select(r, w, x, timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
417 if self.sock not in r:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
418 count = count - 1
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
419 if count < 0: raise RuntimeError('timeout')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
420 if timeout < 25: timeout = timeout *2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
421 ## print 'RESEND', timeout, count
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
422 self.sock.send(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
423 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
424 reply = self.sock.recv(BUFSIZE)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
425 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
426 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
427 xid, verf = u.unpack_replyheader()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
428 if xid != self.lastxid:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
429 ## print 'BAD xid'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
430 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
431 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
432
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
433
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
434 # Client using UDP broadcast to a specific port
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 class RawBroadcastUDPClient(RawUDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
437
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
438 def __init__(self, bcastaddr, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
439 RawUDPClient.__init__(self, bcastaddr, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
440 self.reply_handler = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
441 self.timeout = 30
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
442
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
443 def connsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
444 # Don't connect -- use sendto
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
445 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
446
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
447 def set_reply_handler(self, reply_handler):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
448 self.reply_handler = reply_handler
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_timeout(self, timeout):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
451 self.timeout = timeout # Use None for infinite timeout
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 make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
454 if pack_func is None and args is not None:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
455 raise TypeError('non-null args with null pack_func')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
456 self.start_call(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
457 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
458 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
459 call = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
460 self.sock.sendto(call, (self.host, self.port))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
461 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
462 from select import select
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
463 except ImportError:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
464 print('WARNING: select not found, broadcast will hang')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
465 select = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
466 BUFSIZE = 8192 # Max UDP buffer size (for reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
467 replies = []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
468 if unpack_func is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
469 def dummy(): pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
470 unpack_func = dummy
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
471 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
472 r, w, x = [self.sock], [], []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
473 if select:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
474 if self.timeout is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
475 r, w, x = select(r, w, x)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
476 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
477 r, w, x = select(r, w, x, self.timeout)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
478 if self.sock not in r:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
479 break
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
480 reply, fromaddr = self.sock.recvfrom(BUFSIZE)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
481 u = self.unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
482 u.reset(reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
483 xid, verf = u.unpack_replyheader()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
484 if xid != self.lastxid:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
485 ## print 'BAD xid'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
486 continue
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
487 reply = unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
488 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
489 replies.append((reply, fromaddr))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
490 if self.reply_handler:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
491 self.reply_handler(reply, fromaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
492 return replies
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
493
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
494
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
495 # Port mapper interface
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 # Program number, version and (fixed!) port number
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
498 PMAP_PROG = 100000
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
499 PMAP_VERS = 2
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
500 PMAP_PORT = 111
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
501
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
502 # Procedure numbers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
503 PMAPPROC_NULL = 0 # (void) -> void
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
504 PMAPPROC_SET = 1 # (mapping) -> bool
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
505 PMAPPROC_UNSET = 2 # (mapping) -> bool
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
506 PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
507 PMAPPROC_DUMP = 4 # (void) -> pmaplist
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
508 PMAPPROC_CALLIT = 5 # (call_args) -> call_result
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
509
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
510 # 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
511
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
512 IPPROTO_TCP = 6
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
513 IPPROTO_UDP = 17
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 # A pmaplist is a variable-length list of mappings, as follows:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
516 # either (1, mapping, pmaplist) or (0).
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 call_args is (prog, vers, proc, args) where args is opaque;
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
519 # a call_result is (port, res) where res is opaque.
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
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
522 class PortMapperPacker(Packer):
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 def pack_mapping(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
525 prog, vers, prot, port = mapping
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
526 self.pack_uint(prog)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
527 self.pack_uint(vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
528 self.pack_uint(prot)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
529 self.pack_uint(port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
530
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
531 def pack_pmaplist(self, list):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
532 self.pack_list(list, self.pack_mapping)
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_call_args(self, ca):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
535 prog, vers, proc, args = ca
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
536 self.pack_uint(prog)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
537 self.pack_uint(vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
538 self.pack_uint(proc)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
539 self.pack_opaque(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
540
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
541
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
542 class PortMapperUnpacker(Unpacker):
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 def unpack_mapping(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
545 prog = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
546 vers = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
547 prot = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
548 port = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
549 return prog, vers, prot, port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
550
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
551 def unpack_pmaplist(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
552 return self.unpack_list(self.unpack_mapping)
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_call_result(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
555 port = self.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
556 res = self.unpack_opaque()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
557 return port, res
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
558
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
559
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
560 class PartialPortMapperClient:
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 def addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
563 self.packer = PortMapperPacker()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
564 self.unpacker = PortMapperUnpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
565
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
566 def Set(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
567 return self.make_call(PMAPPROC_SET, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
568 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
569 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
570
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
571 def Unset(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
572 return self.make_call(PMAPPROC_UNSET, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
573 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
574 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
575
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
576 def Getport(self, mapping):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
577 return self.make_call(PMAPPROC_GETPORT, mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
578 self.packer.pack_mapping, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
579 self.unpacker.unpack_uint)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
580
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
581 def Dump(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
582 return self.make_call(PMAPPROC_DUMP, None, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
583 None, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
584 self.unpacker.unpack_pmaplist)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
585
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
586 def Callit(self, ca):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
587 return self.make_call(PMAPPROC_CALLIT, ca, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
588 self.packer.pack_call_args, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
589 self.unpacker.unpack_call_result)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
590
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
591
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
592 class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
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 def __init__(self, host, port=PMAP_PORT, timeout_seconds=None):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
595 RawTCPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
596 host, PMAP_PROG, PMAP_VERS, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
597 self.select_timeout_seconds=timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
598
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
599
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
600 class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
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 def __init__(self, host, port=PMAP_PORT):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
603 RawUDPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
604 host, PMAP_PROG, PMAP_VERS, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
605
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
606 class BroadcastUDPPortMapperClient(PartialPortMapperClient, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
607 RawBroadcastUDPClient):
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 def __init__(self, bcastaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
610 RawBroadcastUDPClient.__init__(self, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
611 bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
612
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
613
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
614 # Generic clients that find their server through the Port mapper
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 class TCPClient(RawTCPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
617
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
618 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
619
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
620 self.select_timeout_seconds=timeout_seconds
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
621 if portmap_proxy_host is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
622 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
623 pmap = TCPPortMapperClient(portmap_proxy_host, portmap_proxy_port,timeout_seconds)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
624 port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
625 pmap.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
626 if port == 0:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
627 raise RuntimeError('program not registered')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
628 RawTCPClient.__init__(self, host, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
629
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
630
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
631 class UDPClient(RawUDPClient):
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 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
634 if portmap_proxy_host is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
635 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
636 pmap = UDPPortMapperClient(portmap_proxy_host, portmap_proxy_port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
637 port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
638 pmap.close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
639 if port == 0:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
640 raise RuntimeError('program not registered')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
641 RawUDPClient.__init__(self, host, prog, vers, port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
642
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
643
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
644 class BroadcastUDPClient(Client):
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 def __init__(self, bcastaddr, prog, vers):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
647 self.pmap = BroadcastUDPPortMapperClient(bcastaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
648 self.pmap.set_reply_handler(self.my_reply_handler)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
649 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
650 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
651 self.user_reply_handler = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
652 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
653
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
654 def close(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
655 self.pmap.close()
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 set_reply_handler(self, reply_handler):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
658 self.user_reply_handler = reply_handler
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_timeout(self, timeout):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
661 self.pmap.set_timeout(timeout)
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 my_reply_handler(self, reply, fromaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
664 port, res = reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
665 self.unpacker.reset(res)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
666 result = self.unpack_func()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
667 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
668 self.replies.append((result, fromaddr))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
669 if self.user_reply_handler is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
670 self.user_reply_handler(result, fromaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
671
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
672 def make_call(self, proc, args, pack_func, unpack_func):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
673 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
674 if pack_func:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
675 pack_func(args)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
676 if unpack_func is None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
677 def dummy(): pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
678 self.unpack_func = dummy
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
679 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
680 self.unpack_func = unpack_func
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
681 self.replies = []
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
682 packed_args = self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
683 dummy_replies = self.pmap.Callit( \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
684 (self.prog, self.vers, proc, packed_args))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
685 return self.replies
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
686
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
687
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
688 # Server classes
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 # These are not symmetric to the Client classes
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
691 # XXX No attempt is made to provide authorization hooks yet
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 class Server:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
694
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
695 def __init__(self, host, prog, vers, port):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
696 self.host = host # Should normally be '' for default interface
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
697 self.prog = prog
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
698 self.vers = vers
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
699 self.port = port # Should normally be 0 for random port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
700 self.makesocket() # Assigns to self.sock and self.prot
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
701 self.bindsocket()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
702 self.host, self.port = self.sock.getsockname()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
703 self.addpackers()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
704
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
705 def handle(self, call):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
706 # Don't use unpack_header but parse the header piecewise
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
707 # 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
708 self.unpacker.reset(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
709 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
710 xid = self.unpacker.unpack_uint()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
711 self.packer.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
712 temp = self.unpacker.unpack_enum()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
713 if temp != CALL:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
714 return None # Not worthy of a reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
715 self.packer.pack_uint(REPLY)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
716 temp = self.unpacker.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
717 if temp != RPCVERSION:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
718 self.packer.pack_uint(MSG_DENIED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
719 self.packer.pack_uint(RPC_MISMATCH)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
720 self.packer.pack_uint(RPCVERSION)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
721 self.packer.pack_uint(RPCVERSION)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
722 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
723 self.packer.pack_uint(MSG_ACCEPTED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
724 self.packer.pack_auth((AUTH_NULL, make_auth_null()))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
725 prog = self.unpacker.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
726 if prog != self.prog:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
727 self.packer.pack_uint(PROG_UNAVAIL)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
728 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
729 vers = self.unpacker.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
730 if vers != self.vers:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
731 self.packer.pack_uint(PROG_MISMATCH)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
732 self.packer.pack_uint(self.vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
733 self.packer.pack_uint(self.vers)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
734 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
735 proc = self.unpacker.unpack_uint()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
736 methname = 'handle_' + repr(proc)
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
737 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
738 meth = getattr(self, methname)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
739 except AttributeError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
740 self.packer.pack_uint(PROC_UNAVAIL)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
741 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
742 cred = self.unpacker.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
743 verf = self.unpacker.unpack_auth()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
744 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
745 meth() # Unpack args, call turn_around(), pack reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
746 except (EOFError, GarbageArgs):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
747 # Too few or too many arguments
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
748 self.packer.reset()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
749 self.packer.pack_uint(xid)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
750 self.packer.pack_uint(REPLY)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
751 self.packer.pack_uint(MSG_ACCEPTED)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
752 self.packer.pack_auth((AUTH_NULL, make_auth_null()))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
753 self.packer.pack_uint(GARBAGE_ARGS)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
754 return self.packer.get_buf()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
755
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
756 def turn_around(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
757 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
758 self.unpacker.done()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
759 except RuntimeError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
760 raise GarbageArgs
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
761 self.packer.pack_uint(SUCCESS)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
762
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
763 def handle_0(self): # Handle NULL message
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
764 self.turn_around()
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 makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
767 # This MUST be overridden
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
768 raise RuntimeError('makesocket not defined')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
769
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
770 def bindsocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
771 # Override this to bind to a different port (e.g. reserved)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
772 self.sock.bind((self.host, self.port))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
773
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
774 def addpackers(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
775 # Override this to use derived classes from Packer/Unpacker
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
776 self.packer = Packer()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
777 self.unpacker = Unpacker('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
778
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
779
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
780 class TCPServer(Server):
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 def register(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
783 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
784 p = TCPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
785 if not p.Set(mapping):
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
786 raise RuntimeError('register failed')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
787
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
788 def unregister(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
789 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
790 p = TCPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
791 if not p.Unset(mapping):
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
792 raise RuntimeError('unregister failed')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
793
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
794 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
795 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
796 self.prot = IPPROTO_TCP
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
797
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
798 def loop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
799 self.sock.listen(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
800 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
801 self.session(self.sock.accept())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
802
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
803 def session(self, connection):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
804 sock, (host, port) = connection
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
805 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
806 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
807 call = recvrecord(sock)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
808 except EOFError:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
809 break
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
810 except socket.error as msg:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
811 print('socket error:', msg)
19
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 reply = self.handle(call)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
814 if reply is not None:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
815 sendrecord(sock, reply)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
816
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
817 def forkingloop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
818 # Like loop but uses forksession()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
819 self.sock.listen(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
820 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
821 self.forksession(self.sock.accept())
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
822
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
823 def forksession(self, connection):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
824 # Like session but forks off a subprocess
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
825 import os
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
826 # Wait for deceased children
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
827 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
828 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
829 pid, sts = os.waitpid(0, 1)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
830 except os.error:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
831 pass
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
832 pid = None
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
833 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
834 pid = os.fork()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
835 if pid: # Parent
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
836 connection[0].close()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
837 return
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
838 # Child
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
839 self.session(connection)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
840 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
841 # Make sure we don't fall through in the parent
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
842 if pid == 0:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
843 os._exit(0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
844
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
845
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
846 class UDPServer(Server):
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 def register(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
849 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
850 p = UDPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
851 if not p.Set(mapping):
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
852 raise RuntimeError('register failed')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
853
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
854 def unregister(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
855 mapping = self.prog, self.vers, self.prot, self.port
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
856 p = UDPPortMapperClient(self.host)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
857 if not p.Unset(mapping):
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
858 raise RuntimeError('unregister failed')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
859
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
860 def makesocket(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
861 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
862 self.prot = IPPROTO_UDP
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
863
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
864 def loop(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
865 while 1:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
866 self.session()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
867
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
868 def session(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
869 call, host_port = self.sock.recvfrom(8192)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
870 reply = self.handle(call)
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
871 if reply != None:
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
872 self.sock.sendto(reply, host_port)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
873
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
874
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
875 # Simple test program -- dump local portmapper status
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 def test():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
878 pmap = UDPPortMapperClient('')
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
879 list = pmap.Dump()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
880 list.sort()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
881 for prog, vers, prot, port in list:
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
882 print(prog, vers, end=' ')
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
883 if prot == IPPROTO_TCP: print('tcp', end=' ')
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
884 elif prot == IPPROTO_UDP: print('udp', end=' ')
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
885 else: print(prot, end=' ')
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
886 print(port)
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
887
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
888
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
889 # Test program for broadcast operation -- dump everybody's portmapper status
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 def testbcast():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
892 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
893 if sys.argv[1:]:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
894 bcastaddr = sys.argv[1]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
895 else:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
896 bcastaddr = '<broadcast>'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
897 def rh(reply, fromaddr):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
898 host, port = fromaddr
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
899 print(host + '\t' + repr(reply))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
900 pmap = BroadcastUDPPortMapperClient(bcastaddr)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
901 pmap.set_reply_handler(rh)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
902 pmap.set_timeout(5)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
903 replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0))
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
904
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
905
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
906 # Test program for server, with corresponding client
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
907 # On machine A: python -c 'import rpc; rpc.testsvr()'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
908 # On machine B: python -c 'import rpc; rpc.testclt()' A
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
909 # (A may be == B)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
910
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
911 def testsvr():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
912 # Simple test class -- proc 1 doubles its string argument as reply
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
913 class S(UDPServer):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
914 def handle_1(self):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
915 arg = self.unpacker.unpack_string()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
916 self.turn_around()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
917 print('RPC function 1 called, arg', repr(arg))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
918 self.packer.pack_string(arg + arg)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
919 #
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
920 s = S('', 0x20000000, 1, 0)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
921 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
922 s.unregister()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
923 except RuntimeError as msg:
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
924 print('RuntimeError:', msg, '(ignored)')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
925 s.register()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
926 print('Service started...')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
927 try:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
928 s.loop()
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
929 finally:
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
930 s.unregister()
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
931 print('Service interrupted.')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
932
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
933
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
934 def testclt():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
935 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
936 if sys.argv[1:]: host = sys.argv[1]
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
937 else: host = ''
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
938 # Client for above server
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
939 class C(UDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
940 def call_1(self, arg):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
941 return self.make_call(1, arg, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
942 self.packer.pack_string, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
943 self.unpacker.unpack_string)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
944 c = C(host, 0x20000000, 1)
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
945 print('making call...')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
946 reply = c.call_1('hello, world, ')
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
947 print('call returned', repr(reply))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
948
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
949 def testclt2():
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
950 import sys
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
951 host = '127.0.0.1'
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
952 # Client for above server
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
953 class C(UDPClient):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
954 def call_1(self, arg):
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
955 return self.make_call(1, arg, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
956 self.packer.pack_string, \
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
957 self.unpacker.unpack_string)
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
958 c = C(host, 0x20000000, 1)
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
959 print('making call...')
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
960 reply = c.call_1('hello, world, ')
56
91b476ebc0f2 Run through 2to3
Daniel O'Connor <doconnor@gsoft.com.au>
parents: 19
diff changeset
961 print('call returned', repr(reply))
19
cba1c44060f5 Copied from
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
962