Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 79f85ee

Browse files
committed
Changed mkcred/mkverf interface; added makesocket hook and changed init
interfaces; added bindresvport call.
1 parent c91d60a commit 79f85ee

1 file changed

Lines changed: 106 additions & 54 deletions

File tree

Demo/rpc/rpc.py

Lines changed: 106 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
# XXX The UDP version of the protocol resends requests when it does
77
# XXX not receive a timely reply -- use only for idempotent calls!
88

9+
# XXX There is no provision for call timeout on TCP connections
10+
911
import xdr
1012
import socket
1113
import os
@@ -160,51 +162,78 @@ def make_auth_unix_default():
160162
gid = getgid()
161163
except ImportError:
162164
uid = gid = 0
163-
return make_auth_unix(0, socket.gethostname(), uid, gid, [])
165+
import time
166+
return make_auth_unix(time.time(), socket.gethostname(), uid, gid, [])
164167

165168

166169
# Common base class for clients
167170

168171
class Client:
169172

170-
def init(self, host, prog, vers, port, type):
173+
def init(self, host, prog, vers, port):
171174
self.host = host
172175
self.prog = prog
173176
self.vers = vers
174177
self.port = port
175-
self.type = type
176-
self.sock = socket.socket(socket.AF_INET, type)
178+
self.makesocket() # Assigns to self.sock
179+
self.bindsocket()
177180
self.sock.connect((host, port))
178181
self.lastxid = 0
179182
self.addpackers()
180183
self.cred = None
181184
self.verf = None
182185
return self
183186

184-
def Null(self): # Procedure 0 is always like this
185-
self.start_call(0)
186-
self.do_call(0)
187-
self.end_call()
188-
189187
def close(self):
190188
self.sock.close()
191189

192-
# Functions that may be overridden by specific derived classes
190+
def makesocket(self):
191+
# This MUST be overridden
192+
raise RuntimeError, 'makesocket not defined'
193+
194+
def bindsocket(self):
195+
# Override this to bind to a different port (e.g. reserved)
196+
self.sock.bind(('', 0))
193197

194198
def addpackers(self):
199+
# Override this to use derived classes from Packer/Unpacker
195200
self.packer = Packer().init()
196201
self.unpacker = Unpacker().init('')
197202

198-
def mkcred(self, proc):
203+
def start_call(self, proc):
204+
# Don't override this
205+
self.lastxid = xid = self.lastxid + 1
206+
cred = self.mkcred()
207+
verf = self.mkverf()
208+
p = self.packer
209+
p.reset()
210+
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
211+
212+
def do_call(self, *rest):
213+
# This MUST be overridden
214+
raise RuntimeError, 'do_call not defined'
215+
216+
def end_call(self):
217+
# Don't override this
218+
self.unpacker.done()
219+
220+
def mkcred(self):
221+
# Override this to use more powerful credentials
199222
if self.cred == None:
200223
self.cred = (AUTH_NULL, make_auth_null())
201224
return self.cred
202225

203-
def mkverf(self, proc):
226+
def mkverf(self):
227+
# Override this to use a more powerful verifier
204228
if self.verf == None:
205229
self.verf = (AUTH_NULL, make_auth_null())
206230
return self.verf
207231

232+
def Null(self): # Procedure 0 is always like this
233+
self.start_call(0)
234+
self.do_call(0)
235+
self.end_call()
236+
208237

209238
# Record-Marking standard support
210239

@@ -243,18 +272,38 @@ def recvrecord(sock):
243272
return record
244273

245274

275+
# Try to bind to a reserved port (must be root)
276+
277+
last_resv_port_tried = None
278+
def bindresvport(sock, host):
279+
global last_resv_port_tried
280+
FIRST, LAST = 600, 1024 # Range of ports to try
281+
if last_resv_port_tried == None:
282+
import os
283+
last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
284+
for i in range(last_resv_port_tried, LAST) + \
285+
range(FIRST, last_resv_port_tried):
286+
last_resv_port_tried = i
287+
try:
288+
sock.bind((host, i))
289+
return last_resv_port_tried
290+
except socket.error, (errno, msg):
291+
if errno <> 114:
292+
raise socket.error, (errno, msg)
293+
raise RuntimeError, 'can\'t assign reserved port'
294+
295+
246296
# Raw TCP-based client
247297

248298
class RawTCPClient(Client):
249299

250-
def init(self, host, prog, vers, port):
251-
return Client.init(self, host, prog, vers, port, \
252-
socket.SOCK_STREAM)
300+
def makesocket(self):
301+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
253302

254303
def start_call(self, proc):
255304
self.lastxid = xid = self.lastxid + 1
256-
cred = self.mkcred(proc)
257-
verf = self.mkverf(proc)
305+
cred = self.mkcred()
306+
verf = self.mkverf()
258307
p = self.packer
259308
p.reset()
260309
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
@@ -280,14 +329,13 @@ def end_call(self):
280329

281330
class RawUDPClient(Client):
282331

283-
def init(self, host, prog, vers, port):
284-
return Client.init(self, host, prog, vers, port, \
285-
socket.SOCK_DGRAM)
332+
def makesocket(self):
333+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
286334

287335
def start_call(self, proc):
288336
self.lastxid = xid = self.lastxid + 1
289-
cred = self.mkcred(proc)
290-
verf = self.mkverf(proc)
337+
cred = self.mkcred()
338+
verf = self.mkverf()
291339
p = self.packer
292340
p.reset()
293341
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
@@ -316,15 +364,15 @@ def do_call(self, *rest):
316364
count = count - 1
317365
if count < 0: raise RuntimeError, 'timeout'
318366
if timeout < 25: timeout = timeout *2
319-
print 'RESEND', timeout, count
367+
## print 'RESEND', timeout, count
320368
self.sock.send(call)
321369
continue
322370
reply = self.sock.recv(bufsize)
323371
u = self.unpacker
324372
u.reset(reply)
325373
xid, verf = u.unpack_replyheader()
326374
if xid <> self.lastxid:
327-
print 'BAD xid'
375+
## print 'BAD xid'
328376
continue
329377
break
330378

@@ -334,9 +382,14 @@ def end_call(self):
334382

335383
# Port mapper interface
336384

337-
PMAP_PORT = 111
385+
# XXX CALLIT is not implemented
386+
387+
# Program number, version and (fixed!) port number
338388
PMAP_PROG = 100000
339389
PMAP_VERS = 2
390+
PMAP_PORT = 111
391+
392+
# Procedure numbers
340393
PMAPPROC_NULL = 0 # (void) -> void
341394
PMAPPROC_SET = 1 # (mapping) -> bool
342395
PMAPPROC_UNSET = 2 # (mapping) -> bool
@@ -439,9 +492,9 @@ class TCPClient(RawTCPClient):
439492
def init(self, host, prog, vers):
440493
pmap = TCPPortMapperClient().init(host)
441494
port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
495+
pmap.close()
442496
if port == 0:
443497
raise RuntimeError, 'program not registered'
444-
pmap.close()
445498
return RawTCPClient.init(self, host, prog, vers, port)
446499

447500

@@ -451,45 +504,37 @@ def init(self, host, prog, vers):
451504
pmap = UDPPortMapperClient().init(host)
452505
port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
453506
pmap.close()
507+
if port == 0:
508+
raise RuntimeError, 'program not registered'
454509
return RawUDPClient.init(self, host, prog, vers, port)
455510

456511

457512
# Server classes
458513

514+
# These are not symmetric to the Client classes
515+
# XXX No attempt is made to provide authorization hooks yet
516+
459517
class Server:
460518

461-
def init(self, host, prog, vers, port, type):
519+
def init(self, host, prog, vers, port):
462520
self.host = host # Should normally be '' for default interface
463521
self.prog = prog
464522
self.vers = vers
465523
self.port = port # Should normally be 0 for random port
466-
self.type = type # SOCK_STREAM or SOCK_DGRAM
467-
self.sock = socket.socket(socket.AF_INET, type)
468-
self.sock.bind((host, port))
524+
self.makesocket() # Assigns to self.sock and self.prot
525+
self.bindsocket()
469526
self.host, self.port = self.sock.getsockname()
470527
self.addpackers()
471528
return self
472529

473530
def register(self):
474-
if self.type == socket.SOCK_STREAM:
475-
type = IPPROTO_TCP
476-
elif self.type == socket.SOCK_DGRAM:
477-
type = IPPROTO_UDP
478-
else:
479-
raise ValueError, 'unknown protocol type'
480-
mapping = self.prog, self.vers, type, self.port
531+
mapping = self.prog, self.vers, self.prot, self.port
481532
p = TCPPortMapperClient().init(self.host)
482533
if not p.Set(mapping):
483534
raise RuntimeError, 'register failed'
484535

485536
def unregister(self):
486-
if self.type == socket.SOCK_STREAM:
487-
type = IPPROTO_TCP
488-
elif self.type == socket.SOCK_DGRAM:
489-
type = IPPROTO_UDP
490-
else:
491-
raise ValueError, 'unknown protocol type'
492-
mapping = self.prog, self.vers, type, self.port
537+
mapping = self.prog, self.vers, self.prot, self.port
493538
p = TCPPortMapperClient().init(self.host)
494539
if not p.Unset(mapping):
495540
raise RuntimeError, 'unregister failed'
@@ -555,18 +600,25 @@ def turn_around(self):
555600
def handle_0(self): # Handle NULL message
556601
self.turn_around()
557602

558-
# Functions that may be overridden by specific derived classes
603+
def makesocket(self):
604+
# This MUST be overridden
605+
raise RuntimeError, 'makesocket not defined'
606+
607+
def bindsocket(self):
608+
# Override this to bind to a different port (e.g. reserved)
609+
self.sock.bind((self.host, self.port))
559610

560611
def addpackers(self):
612+
# Override this to use derived classes from Packer/Unpacker
561613
self.packer = Packer().init()
562614
self.unpacker = Unpacker().init('')
563615

564616

565617
class TCPServer(Server):
566618

567-
def init(self, host, prog, vers, port):
568-
return Server.init(self, host, prog, vers, port, \
569-
socket.SOCK_STREAM)
619+
def makesocket(self):
620+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
621+
self.prot = IPPROTO_TCP
570622

571623
def loop(self):
572624
self.sock.listen(0)
@@ -587,13 +639,13 @@ def session(self, connection):
587639

588640
class UDPServer(Server):
589641

590-
def init(self, host, prog, vers, port):
591-
return Server.init(self, host, prog, vers, port, \
592-
socket.SOCK_DGRAM)
642+
def makesocket(self):
643+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
644+
self.prot = IPPROTO_UDP
593645

594646
def loop(self):
595647
while 1:
596-
session()
648+
self.session()
597649

598650
def session(self):
599651
call, host_port = self.sock.recvfrom(8192)
@@ -629,7 +681,7 @@ def test():
629681

630682
def testsvr():
631683
# Simple test class -- proc 1 doubles its string argument as reply
632-
class S(TCPServer):
684+
class S(UDPServer):
633685
def handle_1(self):
634686
arg = self.unpacker.unpack_string()
635687
self.turn_around()
@@ -655,7 +707,7 @@ def testclt():
655707
if sys.argv[1:]: host = sys.argv[1]
656708
else: host = ''
657709
# Client for above server
658-
class C(TCPClient):
710+
class C(UDPClient):
659711
def call_1(self, arg):
660712
self.start_call(1)
661713
self.packer.pack_string(arg)

0 commit comments

Comments
 (0)