Changed mkcred/mkverf interface; added makesocket hook and changed init

interfaces; added bindresvport call.
This commit is contained in:
Guido van Rossum 1992-12-20 14:56:32 +00:00
parent c91d60a640
commit 79f85eedfd
1 changed files with 106 additions and 54 deletions

View File

@ -6,6 +6,8 @@
# XXX The UDP version of the protocol resends requests when it does
# XXX not receive a timely reply -- use only for idempotent calls!
# XXX There is no provision for call timeout on TCP connections
import xdr
import socket
import os
@ -160,20 +162,21 @@ def make_auth_unix_default():
gid = getgid()
except ImportError:
uid = gid = 0
return make_auth_unix(0, socket.gethostname(), uid, gid, [])
import time
return make_auth_unix(time.time(), socket.gethostname(), uid, gid, [])
# Common base class for clients
class Client:
def init(self, host, prog, vers, port, type):
def init(self, host, prog, vers, port):
self.host = host
self.prog = prog
self.vers = vers
self.port = port
self.type = type
self.sock = socket.socket(socket.AF_INET, type)
self.makesocket() # Assigns to self.sock
self.bindsocket()
self.sock.connect((host, port))
self.lastxid = 0
self.addpackers()
@ -181,30 +184,56 @@ class Client:
self.verf = None
return self
def Null(self): # Procedure 0 is always like this
self.start_call(0)
self.do_call(0)
self.end_call()
def close(self):
self.sock.close()
# Functions that may be overridden by specific derived classes
def makesocket(self):
# This MUST be overridden
raise RuntimeError, 'makesocket not defined'
def bindsocket(self):
# Override this to bind to a different port (e.g. reserved)
self.sock.bind(('', 0))
def addpackers(self):
# Override this to use derived classes from Packer/Unpacker
self.packer = Packer().init()
self.unpacker = Unpacker().init('')
def mkcred(self, proc):
def start_call(self, proc):
# Don't override this
self.lastxid = xid = self.lastxid + 1
cred = self.mkcred()
verf = self.mkverf()
p = self.packer
p.reset()
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
def do_call(self, *rest):
# This MUST be overridden
raise RuntimeError, 'do_call not defined'
def end_call(self):
# Don't override this
self.unpacker.done()
def mkcred(self):
# Override this to use more powerful credentials
if self.cred == None:
self.cred = (AUTH_NULL, make_auth_null())
return self.cred
def mkverf(self, proc):
def mkverf(self):
# Override this to use a more powerful verifier
if self.verf == None:
self.verf = (AUTH_NULL, make_auth_null())
return self.verf
def Null(self): # Procedure 0 is always like this
self.start_call(0)
self.do_call(0)
self.end_call()
# Record-Marking standard support
@ -243,18 +272,38 @@ def recvrecord(sock):
return record
# Try to bind to a reserved port (must be root)
last_resv_port_tried = None
def bindresvport(sock, host):
global last_resv_port_tried
FIRST, LAST = 600, 1024 # Range of ports to try
if last_resv_port_tried == None:
import os
last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
for i in range(last_resv_port_tried, LAST) + \
range(FIRST, last_resv_port_tried):
last_resv_port_tried = i
try:
sock.bind((host, i))
return last_resv_port_tried
except socket.error, (errno, msg):
if errno <> 114:
raise socket.error, (errno, msg)
raise RuntimeError, 'can\'t assign reserved port'
# Raw TCP-based client
class RawTCPClient(Client):
def init(self, host, prog, vers, port):
return Client.init(self, host, prog, vers, port, \
socket.SOCK_STREAM)
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def start_call(self, proc):
self.lastxid = xid = self.lastxid + 1
cred = self.mkcred(proc)
verf = self.mkverf(proc)
cred = self.mkcred()
verf = self.mkverf()
p = self.packer
p.reset()
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
@ -280,14 +329,13 @@ class RawTCPClient(Client):
class RawUDPClient(Client):
def init(self, host, prog, vers, port):
return Client.init(self, host, prog, vers, port, \
socket.SOCK_DGRAM)
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def start_call(self, proc):
self.lastxid = xid = self.lastxid + 1
cred = self.mkcred(proc)
verf = self.mkverf(proc)
cred = self.mkcred()
verf = self.mkverf()
p = self.packer
p.reset()
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
@ -316,7 +364,7 @@ class RawUDPClient(Client):
count = count - 1
if count < 0: raise RuntimeError, 'timeout'
if timeout < 25: timeout = timeout *2
print 'RESEND', timeout, count
## print 'RESEND', timeout, count
self.sock.send(call)
continue
reply = self.sock.recv(bufsize)
@ -324,7 +372,7 @@ class RawUDPClient(Client):
u.reset(reply)
xid, verf = u.unpack_replyheader()
if xid <> self.lastxid:
print 'BAD xid'
## print 'BAD xid'
continue
break
@ -334,9 +382,14 @@ class RawUDPClient(Client):
# Port mapper interface
PMAP_PORT = 111
# XXX CALLIT is not implemented
# Program number, version and (fixed!) port number
PMAP_PROG = 100000
PMAP_VERS = 2
PMAP_PORT = 111
# Procedure numbers
PMAPPROC_NULL = 0 # (void) -> void
PMAPPROC_SET = 1 # (mapping) -> bool
PMAPPROC_UNSET = 2 # (mapping) -> bool
@ -439,9 +492,9 @@ class TCPClient(RawTCPClient):
def init(self, host, prog, vers):
pmap = TCPPortMapperClient().init(host)
port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
pmap.close()
if port == 0:
raise RuntimeError, 'program not registered'
pmap.close()
return RawTCPClient.init(self, host, prog, vers, port)
@ -451,45 +504,37 @@ class UDPClient(RawUDPClient):
pmap = UDPPortMapperClient().init(host)
port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
pmap.close()
if port == 0:
raise RuntimeError, 'program not registered'
return RawUDPClient.init(self, host, prog, vers, port)
# Server classes
# These are not symmetric to the Client classes
# XXX No attempt is made to provide authorization hooks yet
class Server:
def init(self, host, prog, vers, port, type):
def init(self, host, prog, vers, port):
self.host = host # Should normally be '' for default interface
self.prog = prog
self.vers = vers
self.port = port # Should normally be 0 for random port
self.type = type # SOCK_STREAM or SOCK_DGRAM
self.sock = socket.socket(socket.AF_INET, type)
self.sock.bind((host, port))
self.makesocket() # Assigns to self.sock and self.prot
self.bindsocket()
self.host, self.port = self.sock.getsockname()
self.addpackers()
return self
def register(self):
if self.type == socket.SOCK_STREAM:
type = IPPROTO_TCP
elif self.type == socket.SOCK_DGRAM:
type = IPPROTO_UDP
else:
raise ValueError, 'unknown protocol type'
mapping = self.prog, self.vers, type, self.port
mapping = self.prog, self.vers, self.prot, self.port
p = TCPPortMapperClient().init(self.host)
if not p.Set(mapping):
raise RuntimeError, 'register failed'
def unregister(self):
if self.type == socket.SOCK_STREAM:
type = IPPROTO_TCP
elif self.type == socket.SOCK_DGRAM:
type = IPPROTO_UDP
else:
raise ValueError, 'unknown protocol type'
mapping = self.prog, self.vers, type, self.port
mapping = self.prog, self.vers, self.prot, self.port
p = TCPPortMapperClient().init(self.host)
if not p.Unset(mapping):
raise RuntimeError, 'unregister failed'
@ -555,18 +600,25 @@ class Server:
def handle_0(self): # Handle NULL message
self.turn_around()
# Functions that may be overridden by specific derived classes
def makesocket(self):
# This MUST be overridden
raise RuntimeError, 'makesocket not defined'
def bindsocket(self):
# Override this to bind to a different port (e.g. reserved)
self.sock.bind((self.host, self.port))
def addpackers(self):
# Override this to use derived classes from Packer/Unpacker
self.packer = Packer().init()
self.unpacker = Unpacker().init('')
class TCPServer(Server):
def init(self, host, prog, vers, port):
return Server.init(self, host, prog, vers, port, \
socket.SOCK_STREAM)
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.prot = IPPROTO_TCP
def loop(self):
self.sock.listen(0)
@ -587,13 +639,13 @@ class TCPServer(Server):
class UDPServer(Server):
def init(self, host, prog, vers, port):
return Server.init(self, host, prog, vers, port, \
socket.SOCK_DGRAM)
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.prot = IPPROTO_UDP
def loop(self):
while 1:
session()
self.session()
def session(self):
call, host_port = self.sock.recvfrom(8192)
@ -629,7 +681,7 @@ def test():
def testsvr():
# Simple test class -- proc 1 doubles its string argument as reply
class S(TCPServer):
class S(UDPServer):
def handle_1(self):
arg = self.unpacker.unpack_string()
self.turn_around()
@ -655,7 +707,7 @@ def testclt():
if sys.argv[1:]: host = sys.argv[1]
else: host = ''
# Client for above server
class C(TCPClient):
class C(UDPClient):
def call_1(self, arg):
self.start_call(1)
self.packer.pack_string(arg)