summaryrefslogtreecommitdiffstats
path: root/Demo/rpc
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1992-12-14 23:25:04 (GMT)
committerGuido van Rossum <guido@python.org>1992-12-14 23:25:04 (GMT)
commite3cafbe7b85c350d4dbeb2af53fd8fc1ae66689b (patch)
tree3a6030b09829c527c8bb0fdcd6b36f6e9e332fe1 /Demo/rpc
parent5f59d6018e1b49c3bc581a0f69aa2bb1c88ae52b (diff)
downloadcpython-e3cafbe7b85c350d4dbeb2af53fd8fc1ae66689b.zip
cpython-e3cafbe7b85c350d4dbeb2af53fd8fc1ae66689b.tar.gz
cpython-e3cafbe7b85c350d4dbeb2af53fd8fc1ae66689b.tar.bz2
Initial revision
Diffstat (limited to 'Demo/rpc')
-rw-r--r--Demo/rpc/T.py19
-rw-r--r--Demo/rpc/mountclient.py166
-rw-r--r--Demo/rpc/nfsclient.py207
-rw-r--r--Demo/rpc/rpc.py376
-rw-r--r--Demo/rpc/xdr.py141
5 files changed, 909 insertions, 0 deletions
diff --git a/Demo/rpc/T.py b/Demo/rpc/T.py
new file mode 100644
index 0000000..24d5e8a
--- /dev/null
+++ b/Demo/rpc/T.py
@@ -0,0 +1,19 @@
+import sys, os, time
+
+def TSTART():
+ global t0, t1
+ u, s, cu, cs = os.times()
+ t0 = u+cu, s+cs, time.millitimer()
+
+def TSTOP(*label):
+ global t0, t1
+ u, s, cu, cs = os.times()
+ t1 = u+cu, s+cs, time.millitimer()
+ tt = []
+ for i in range(3):
+ tt.append(t1[i] - t0[i])
+ [u, s, r] = tt
+ msg = ''
+ for x in label: msg = msg + (x + ' ')
+ msg = msg + `u` + ' user, ' + `s` + ' sys, ' + `r*0.001` + ' real\n'
+ sys.stderr.write(msg)
diff --git a/Demo/rpc/mountclient.py b/Demo/rpc/mountclient.py
new file mode 100644
index 0000000..021de8c
--- /dev/null
+++ b/Demo/rpc/mountclient.py
@@ -0,0 +1,166 @@
+# Mount RPC client -- RFC 1094 (NFS), Appendix A
+
+# This module demonstrates how to write your own RPC client in Python.
+# Since there is no RPC compiler for Python (yet), you must first
+# create classes derived from Packer and Unpacker to handle the data
+# types for the server you want to interface to. You then write the
+# client class. If you want to support both the TCP and the UDP
+# version of a protocol, use multiple inheritance as shown below.
+
+
+from rpc import Packer, Unpacker, TCPClient, UDPClient
+
+MOUNTPROG = 100005
+MOUNTVERS = 1
+
+FHSIZE = 32
+
+
+# Packer derived class for Mount protocol clients.
+# The only thing we need to pack beyond basic types is an 'fhandle'
+
+class MountPacker(Packer):
+
+ def pack_fhandle(self, fhandle):
+ self.pack_fopaque(FHSIZE, fhandle)
+
+
+# Unpacker derived class for Mount protocol clients.
+# The important types we need to unpack are fhandle, fhstatus,
+# mountlist and exportlist; mountstruct, exportstruct and groups are
+# used to unpack components of mountlist and exportlist and the
+# corresponding functions are passed as function argument to the
+# generic unpack_list function.
+
+class MountUnpacker(Unpacker):
+
+ def unpack_fhandle(self):
+ return self.unpack_fopaque(FHSIZE)
+
+ def unpack_fhstatus(self):
+ status = self.unpack_uint()
+ if status == 0:
+ fh = self.unpack_fhandle()
+ else:
+ fh = None
+ return status, fh
+
+ def unpack_mountlist(self):
+ return self.unpack_list(self.unpack_mountstruct)
+
+ def unpack_mountstruct(self):
+ hostname = self.unpack_string()
+ directory = self.unpack_string()
+ return (hostname, directory)
+
+ def unpack_exportlist(self):
+ return self.unpack_list(self.unpack_exportstruct)
+
+ def unpack_exportstruct(self):
+ filesys = self.unpack_string()
+ groups = self.unpack_groups()
+ return (filesys, groups)
+
+ def unpack_groups(self):
+ return self.unpack_list(self.unpack_string)
+
+
+# These are the procedures specific to the Mount client class.
+# Think of this as a derived class of either TCPClient or UDPClient.
+
+class PartialMountClient:
+
+ # This method is called by Client.init to initialize
+ # self.packer and self.unpacker
+ def addpackers(self):
+ self.packer = MountPacker().init()
+ self.unpacker = MountUnpacker().init('')
+
+ # The methods Mnt, Dump etc. each implement one Remote
+ # Procedure Call. Their general structure is
+ # self.start_call(<procedure-number>)
+ # <pack arguments using self.packer>
+ # self.do_call() # This does the actual message exchange
+ # <unpack reply using self.unpacker>
+ # self.end_call()
+ # return <reply>
+ # If the call fails, an exception is raised by do_call().
+ # If the reply does not match what you unpack, an exception is
+ # raised either during unpacking (if you overrun the buffer)
+ # or by end_call() (if you leave values in the buffer).
+ # Calling packer methods with invalid arguments (e.g. if
+ # invalid arguments were passed from outside) will also result
+ # in exceptions during packing.
+
+ def Mnt(self, directory):
+ self.start_call(1)
+ self.packer.pack_string(directory)
+ self.do_call()
+ stat = self.unpacker.unpack_fhstatus()
+ self.end_call()
+ return stat
+
+ def Dump(self):
+ self.start_call(2)
+ self.do_call()
+ list = self.unpacker.unpack_mountlist()
+ self.end_call()
+ return list
+
+ def Umnt(self, directory):
+ self.start_call(3)
+ self.packer.pack_string(directory)
+ self.do_call()
+ self.end_call()
+
+ def Umntall(self):
+ self.start_call(4)
+ self.do_call()
+ self.end_call()
+
+ def Export(self):
+ self.start_call(5)
+ self.do_call()
+ list = self.unpacker.unpack_exportlist()
+ self.end_call()
+ return list
+
+
+# We turn the partial Mount client into a full one for either protocol
+# by use of multiple inheritance. (In general, when class C has base
+# classes B1...Bn, if x is an instance of class C, methods of x are
+# searched first in C, then in B1, then in B2, ..., finally in Bn.)
+
+class TCPMountClient(PartialMountClient, TCPClient):
+
+ def init(self, host):
+ return TCPClient.init(self, host, MOUNTPROG, MOUNTVERS)
+
+
+class UDPMountClient(PartialMountClient, UDPClient):
+
+ def init(self, host):
+ return UDPClient.init(self, host, MOUNTPROG, MOUNTVERS)
+
+
+# A little test program for the Mount client. This takes a host as
+# command line argument (default the local machine), prints its export
+# list, and attempt to mount and unmount each exported files system.
+
+def test():
+ import sys
+ if sys.argv[1:]: host = sys.argv[1]
+ else: host = ''
+ mcl = UDPMountClient().init(host)
+ list = mcl.Export()
+ for item in list:
+ print item
+ try:
+ mcl.Mnt(item[0])
+ except:
+ print 'Sorry'
+ continue
+ mcl.Umnt(item[0])
+ return
+
+#test()
diff --git a/Demo/rpc/nfsclient.py b/Demo/rpc/nfsclient.py
new file mode 100644
index 0000000..2260139
--- /dev/null
+++ b/Demo/rpc/nfsclient.py
@@ -0,0 +1,207 @@
+# NFS RPC client -- RFC 1094
+
+# (See mountclient.py for some hints on how to write RPC clients in
+# Python in general)
+
+from rpc import UDPClient, TCPClient
+from mountclient import FHSIZE, MountPacker, MountUnpacker
+
+NFS_PROGRAM = 100003
+NFS_VERSION = 2
+
+# enum stat
+NFS_OK = 0
+# (...many error values...)
+
+# enum ftype
+NFNON = 0
+NFREG = 1
+NFDIR = 2
+NFBLK = 3
+NFCHR = 4
+NFLNK = 5
+
+
+class NFSPacker(MountPacker):
+
+ def pack_sattrargs(self, sa):
+ file, attributes = sa
+ self.pack_fhandle(file)
+ self.pack_sattr(attributes)
+
+ def pack_sattr(self, sa):
+ mode, uid, gid, size, atime, mtime = sa
+ self.pack_uint(mode)
+ self.pack_uint(uid)
+ self.pack_uint(gid)
+ self.pack_uint(size)
+ self.pack_timeval(atime)
+ self.pack_timeval(mtime)
+
+ def pack_diropargs(self, da):
+ dir, name = da
+ self.pack_fhandle(dir)
+ self.pack_string(name)
+
+ def pack_readdirargs(self, ra):
+ dir, cookie, count = ra
+ self.pack_fhandle(dir)
+ self.pack_uint(cookie)
+ self.pack_uint(count)
+
+ def pack_timeval(self, tv):
+ secs, usecs = tv
+ self.pack_uint(secs)
+ self.pack_uint(usecs)
+
+
+class NFSUnpacker(MountUnpacker):
+
+ def unpack_readdirres(self):
+ status = self.unpack_enum()
+ if status == NFS_OK:
+ entries = self.unpack_list(self.unpack_entry)
+ eof = self.unpack_bool()
+ rest = (entries, eof)
+ else:
+ rest = None
+ return (status, rest)
+
+ def unpack_entry(self):
+ fileid = self.unpack_uint()
+ name = self.unpack_string()
+ cookie = self.unpack_uint()
+ return (fileid, name, cookie)
+
+ def unpack_diropres(self):
+ status = self.unpack_enum()
+ if status == NFS_OK:
+ fh = self.unpack_fhandle()
+ fa = self.unpack_fattr()
+ rest = (fh, fa)
+ else:
+ rest = None
+ return (status, rest)
+
+ def unpack_attrstat(self):
+ status = self.unpack_enum()
+ if status == NFS_OK:
+ attributes = self.unpack_fattr()
+ else:
+ attributes = None
+ return status, attributes
+
+ def unpack_fattr(self):
+ type = self.unpack_enum()
+ mode = self.unpack_uint()
+ nlink = self.unpack_uint()
+ uid = self.unpack_uint()
+ gid = self.unpack_uint()
+ size = self.unpack_uint()
+ blocksize = self.unpack_uint()
+ rdev = self.unpack_uint()
+ blocks = self.unpack_uint()
+ fsid = self.unpack_uint()
+ fileid = self.unpack_uint()
+ atime = self.unpack_timeval()
+ mtime = self.unpack_timeval()
+ ctime = self.unpack_timeval()
+ return (type, mode, nlink, uid, gid, size, blocksize, \
+ rdev, blocks, fsid, fileid, atime, mtime, ctime)
+
+ def unpack_timeval(self):
+ secs = self.unpack_uint()
+ usecs = self.unpack_uint()
+ return (secs, usecs)
+
+
+class NFSClient(UDPClient):
+
+ def init(self, host):
+ return UDPClient.init(self, host, NFS_PROGRAM, NFS_VERSION)
+
+ def addpackers(self):
+ self.packer = NFSPacker().init()
+ self.unpacker = NFSUnpacker().init('')
+
+ def Getattr(self, fh):
+ self.start_call(1)
+ self.packer.pack_fhandle(fh)
+ self.do_call()
+ as = self.unpacker.unpack_attrstat()
+ self.end_call()
+ return as
+
+ def Setattr(self, sa):
+ self.start_call(2)
+ self.packer.pack_sattrargs(sa)
+ self.do_call()
+ as = self.unpacker.unpack_attrstat()
+ self.end_call()
+ return as
+
+ # Root() is obsolete
+
+ def Lookup(self, da):
+ self.start_call(4)
+ self.packer.pack_diropargs(da)
+ self.do_call()
+ dr = self.unpacker.unpack_diropres()
+ self.end_call()
+ return dr
+
+ # ...
+
+ def Readdir(self, ra):
+ self.start_call(16)
+ self.packer.pack_readdirargs(ra)
+ self.do_call()
+ rr = self.unpacker.unpack_readdirres()
+ self.end_call()
+ return rr
+
+ # Shorthand to get the entire contents of a directory
+ def Listdir(self, dir):
+ list = []
+ ra = (dir, 0, 16)
+ while 1:
+ (status, rest) = self.Readdir(ra)
+ if status <> NFS_OK:
+ break
+ entries, eof = rest
+ last_cookie = None
+ for fileid, name, cookie in entries:
+ print (fileid, name, cookie) # XXX
+ list.append(fileid, name)
+ last_cookie = cookie
+ if eof or not last_cookie:
+ break
+ ra = (ra[0], last_cookie, ra[2])
+ return list
+
+
+def test():
+ import sys
+ if sys.argv[1:]: host = sys.argv[1]
+ else: host = ''
+ if sys.argv[2:]: filesys = sys.argv[2]
+ else: filesys = None
+ from mountclient import UDPMountClient, TCPMountClient
+ mcl = TCPMountClient().init(host)
+ if filesys == None:
+ list = mcl.Export()
+ for item in list:
+ print item
+ return
+ sf = mcl.Mnt(filesys)
+ print sf
+ fh = sf[1]
+ if fh:
+ ncl = NFSClient().init(host)
+ as = ncl.Getattr(fh)
+ print as
+ list = ncl.Listdir(fh)
+ for item in list: print item
+ mcl.Unmnt(filesys)
+
+test()
diff --git a/Demo/rpc/rpc.py b/Demo/rpc/rpc.py
new file mode 100644
index 0000000..ba3bd54
--- /dev/null
+++ b/Demo/rpc/rpc.py
@@ -0,0 +1,376 @@
+# Implement (a subset of) Sun RPC, version 2 -- RFC1057.
+
+import xdr
+import socket
+import os
+
+RPCVERSION = 2
+
+CALL = 0
+REPLY = 1
+
+AUTH_NULL = 0
+AUTH_UNIX = 1
+AUTH_SHORT = 2
+AUTH_DES = 3
+
+MSG_ACCEPTED = 0
+MSG_DENIED = 1
+
+SUCCESS = 0 # RPC executed successfully
+PROG_UNAVAIL = 1 # remote hasn't exported program
+PROG_MISMATCH = 2 # remote can't support version #
+PROC_UNAVAIL = 3 # program can't support procedure
+GARBAGE_ARGS = 4 # procedure can't decode params
+
+RPC_MISMATCH = 0 # RPC version number != 2
+AUTH_ERROR = 1 # remote can't authenticate caller
+
+AUTH_BADCRED = 1 # bad credentials (seal broken)
+AUTH_REJECTEDCRED = 2 # client must begin new session
+AUTH_BADVERF = 3 # bad verifier (seal broken)
+AUTH_REJECTEDVERF = 4 # verifier expired or replayed
+AUTH_TOOWEAK = 5 # rejected for security reasons
+
+
+class Packer(xdr.Packer):
+
+ def pack_auth(self, auth):
+ flavor, stuff = auth
+ self.pack_enum(flavor)
+ self.pack_opaque(stuff)
+
+ def pack_auth_unix(self, stamp, machinename, uid, gid, gids):
+ self.pack_uint(stamp)
+ self.pack_string(machinename)
+ self.pack_uint(uid)
+ self.pack_uint(gid)
+ self.pack_uint(len(gids))
+ for i in gids:
+ self.pack_uint(i)
+
+ def pack_callheader(self, xid, prog, vers, proc, cred, verf):
+ self.pack_uint(xid)
+ self.pack_enum(CALL)
+ self.pack_uint(RPCVERSION)
+ self.pack_uint(prog)
+ self.pack_uint(vers)
+ self.pack_uint(proc)
+ self.pack_auth(cred)
+ self.pack_auth(verf)
+ # Caller must add procedure-specific part of call
+
+ def pack_replyheader(self, xid, verf):
+ self.pack_uint(xid)
+ self.pack_enum(REPLY)
+ self.pack_uint(MSG_ACCEPTED)
+ self.pack_auth(verf)
+ self.pack_enum(SUCCESS)
+ # Caller must add procedure-specific part of reply
+
+
+class Unpacker(xdr.Unpacker):
+
+ def unpack_auth(self):
+ flavor = self.unpack_enum()
+ stuff = self.unpack_opaque()
+ return (flavor, stuff)
+
+ def unpack_replyheader(self):
+ xid = self.unpack_uint()
+ mtype = self.unpack_enum()
+ if mtype <> REPLY:
+ raise RuntimeError, 'no REPLY but ' + str(mtype)
+ stat = self.unpack_enum()
+ if stat <> MSG_ACCEPTED:
+ if stat == MSG_DENIED:
+ stat = self.unpack_enum()
+ if stat == RPC_MISMATCH:
+ low = self.unpack_uint()
+ high = self.unpack_uint()
+ raise 'RPC_MISMATCH', (low, high)
+ if stat == AUTH_ERROR:
+ stat = self.unpack_uint()
+ raise 'AUTH_ERROR', str(stat)
+ raise 'MSG_REJECTED', str(stat)
+ raise RuntimeError, 'no MSG_ACCEPTED but ' + str(stat)
+ verf = self.unpack_auth()
+ stat = self.unpack_enum()
+ if stat <> SUCCESS:
+ raise RuntimeError, 'no SUCCESS but ' + str(stat)
+ return xid, verf
+ # Caller must get procedure-specific part of reply
+
+
+# Common base class for clients
+
+class Client:
+
+ def init(self, host, prog, vers, port, type):
+ self.host = host
+ self.prog = prog
+ self.vers = vers
+ self.port = port
+ self.type = type
+ self.sock = socket.socket(socket.AF_INET, type)
+ self.sock.connect((host, port))
+ self.lastxid = 0
+ self.addpackers()
+ self.cred = None
+ 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 addpackers(self):
+ self.packer = Packer().init()
+ self.unpacker = Unpacker().init('')
+
+ def mkcred(self, proc):
+ if self.cred == None:
+ p = Packer().init()
+ p.pack_auth_unix(0, socket.gethostname(), \
+ os.getuid(), os.getgid(), [])
+ self.cred = p.get_buf()
+ return (AUTH_UNIX, self.cred)
+
+ def mkverf(self, proc):
+ return (AUTH_NULL, '')
+
+
+# Record-Marking standard support
+
+def sendfrag(sock, last, frag):
+ x = len(frag)
+ if last: x = x | 0x80000000L
+ header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
+ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
+ sock.send(header + frag)
+
+def sendrecord(sock, record):
+ sendfrag(sock, 1, record)
+
+def recvfrag(sock):
+ header = sock.recv(4)
+ x = long(ord(header[0]))<<24 | ord(header[1])<<16 | \
+ ord(header[2])<<8 | ord(header[3])
+ last = ((x & 0x80000000) != 0)
+ n = int(x & 0x7fffffff)
+ frag = ''
+ while n > 0:
+ buf = sock.recv(n)
+ if not buf: raise EOFError
+ n = n - len(buf)
+ frag = frag + buf
+ return last, frag
+
+def recvrecord(sock):
+ record = ''
+ last = 0
+ while not last:
+ last, frag = recvfrag(sock)
+ record = record + frag
+ return record
+
+
+# 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 start_call(self, proc):
+ self.lastxid = xid = self.lastxid + 1
+ cred = self.mkcred(proc)
+ verf = self.mkverf(proc)
+ p = self.packer
+ p.reset()
+ p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
+
+ def do_call(self, *rest):
+ # rest is used for UDP buffer size; ignored for TCP
+ call = self.packer.get_buf()
+ sendrecord(self.sock, call)
+ reply = recvrecord(self.sock)
+ u = self.unpacker
+ u.reset(reply)
+ xid, verf = u.unpack_replyheader()
+ if xid <> self.lastxid:
+ # Can't really happen since this is TCP...
+ raise RuntimeError, 'wrong xid in reply ' + `xid` + \
+ ' instead of ' + `self.lastxid`
+
+ def end_call(self):
+ self.unpacker.done()
+
+
+# Raw UDP-based client
+# XXX This class does not recover from missed/duplicated packets!
+
+class RawUDPClient(Client):
+
+ def init(self, host, prog, vers, port):
+ return Client.init(self, host, prog, vers, port, \
+ socket.SOCK_DGRAM)
+
+ def start_call(self, proc):
+ self.lastxid = xid = self.lastxid + 1
+ cred = self.mkcred(proc)
+ verf = self.mkverf(proc)
+ p = self.packer
+ p.reset()
+ p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
+
+ def do_call(self, *rest):
+ if len(rest) == 0:
+ bufsize = 8192
+ elif len(rest) > 1:
+ raise TypeError, 'too many args'
+ else:
+ bufsize = rest[0] + 512
+ call = self.packer.get_buf()
+ self.sock.send(call)
+ # XXX What about time-out and retry?
+ reply = self.sock.recv(bufsize)
+ u = self.unpacker
+ u.reset(reply)
+ xid, verf = u.unpack_replyheader()
+ if xid <> self.lastxid:
+ # XXX Should assume it's an old reply
+ raise RuntimeError, 'wrong xid in reply ' + `xid` + \
+ ' instead of ' + `self.lastxid`
+
+ def end_call(self):
+ self.unpacker.done()
+
+
+# Port mapper interface
+
+PMAP_PORT = 111
+PMAP_PROG = 100000
+PMAP_VERS = 2
+PMAPPROC_NULL = 0 # (void) -> void
+PMAPPROC_SET = 1 # (mapping) -> bool
+PMAPPROC_UNSET = 2 # (mapping) -> bool
+PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
+PMAPPROC_DUMP = 4 # (void) -> pmaplist
+PMAPPROC_CALLIT = 5 # (call_args) -> call_result
+
+# A mapping is (prog, vers, prot, port) and prot is one of:
+
+IPPROTO_TCP = 6
+IPPROTO_UDP = 17
+
+# A pmaplist is a variable-length list of mappings, as follows:
+# either (1, mapping, pmaplist) or (0).
+
+# A call_args is (prog, vers, proc, args) where args is opaque;
+# a call_result is (port, res) where res is opaque.
+
+
+class PortMapperPacker(Packer):
+
+ def pack_mapping(self, mapping):
+ prog, vers, prot, port = mapping
+ self.pack_uint(prog)
+ self.pack_uint(vers)
+ self.pack_uint(prot)
+ self.pack_uint(port)
+
+ def pack_pmaplist(self, list):
+ self.pack_list(list, self.pack_mapping)
+
+
+class PortMapperUnpacker(Unpacker):
+
+ def unpack_mapping(self):
+ prog = self.unpack_uint()
+ vers = self.unpack_uint()
+ prot = self.unpack_uint()
+ port = self.unpack_uint()
+ return prog, vers, prot, port
+
+ def unpack_pmaplist(self):
+ return self.unpack_list(self.unpack_mapping)
+
+
+class PartialPortMapperClient:
+
+ def addpackers(self):
+ self.packer = PortMapperPacker().init()
+ self.unpacker = PortMapperUnpacker().init('')
+
+ def Getport(self, mapping):
+ self.start_call(PMAPPROC_GETPORT)
+ self.packer.pack_mapping(mapping)
+ self.do_call(4)
+ port = self.unpacker.unpack_uint()
+ self.end_call()
+ return port
+
+ def Dump(self):
+ self.start_call(PMAPPROC_DUMP)
+ self.do_call(8192-512)
+ list = self.unpacker.unpack_pmaplist()
+ self.end_call()
+ return list
+
+
+class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
+
+ def init(self, host):
+ return RawTCPClient.init(self, \
+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
+
+
+class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
+
+ def init(self, host):
+ return RawUDPClient.init(self, \
+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
+
+
+class TCPClient(RawTCPClient):
+
+ def init(self, host, prog, vers):
+ pmap = TCPPortMapperClient().init(host)
+ port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
+ pmap.close()
+ return RawTCPClient.init(self, host, prog, vers, port)
+
+
+class UDPClient(RawUDPClient):
+
+ def init(self, host, prog, vers):
+ pmap = UDPPortMapperClient().init(host)
+ port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
+ pmap.close()
+ return RawUDPClient.init(self, host, prog, vers, port)
+
+
+def test():
+ import T
+ T.TSTART()
+ pmap = UDPPortMapperClient().init('')
+ T.TSTOP()
+ pmap.Null()
+ T.TSTOP()
+ list = pmap.Dump()
+ T.TSTOP()
+ list.sort()
+ for prog, vers, prot, port in list:
+ print prog, vers,
+ if prot == IPPROTO_TCP: print 'tcp',
+ elif prot == IPPROTO_UDP: print 'udp',
+ else: print prot,
+ print port
diff --git a/Demo/rpc/xdr.py b/Demo/rpc/xdr.py
new file mode 100644
index 0000000..b189b45
--- /dev/null
+++ b/Demo/rpc/xdr.py
@@ -0,0 +1,141 @@
+# Implement (a subset of) Sun XDR -- RFC1014.
+
+
+import struct
+
+
+class Packer:
+
+ def init(self):
+ self.reset()
+ return self
+
+ def reset(self):
+ self.buf = ''
+
+ def get_buf(self):
+ return self.buf
+
+ def pack_uint(self, x):
+ self.buf = self.buf + \
+ (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
+ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
+ if struct.pack('i', 1) == '\0\0\0\1':
+ def pack_uint(self, x):
+ self.buf = self.buf + struct.pack('i', x)
+
+ pack_int = pack_uint
+
+ pack_enum = pack_int
+
+ def pack_bool(self, x):
+ if x: self.buf = self.buf + '\0\0\0\1'
+ else: self.buf = self.buf + '\0\0\0\0'
+
+ def pack_uhyper(self, x):
+ self.pack_uint(x>>32 & 0xffffffff)
+ self.pack_uint(x & 0xffffffff)
+
+ pack_hyper = pack_uhyper
+
+ def pack_fstring(self, n, s):
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ n = ((n+3)/4)*4
+ data = s[:n]
+ data = data + (n - len(data)) * '\0'
+ self.buf = self.buf + data
+
+ pack_fopaque = pack_fstring
+
+ def pack_string(self, s):
+ n = len(s)
+ self.pack_uint(n)
+ self.pack_fstring(n, s)
+
+ pack_opaque = pack_string
+
+ def pack_list(self, list, pack_item):
+ for item in list:
+ self.pack_uint(1)
+ pack_item(list)
+ self.pack_uint(0)
+
+
+class Unpacker:
+
+ def init(self, data):
+ self.reset(data)
+ return self
+
+ def reset(self, data):
+ self.buf = data
+ self.pos = 0
+
+ def done(self):
+ if self.pos < len(self.buf):
+ raise RuntimeError, 'unextracted data remains'
+
+ def unpack_uint(self):
+ i = self.pos
+ self.pos = j = i+4
+ data = self.buf[i:j]
+ x = long(ord(data[0]))<<24 | ord(data[1])<<16 | \
+ ord(data[2])<<8 | ord(data[3])
+ # Return a Python long only if the value is not representable
+ # as a nonnegative Python int
+ if x < 0x80000000L: x = int(x)
+ return x
+ if struct.unpack('i', '\0\0\0\1') == 1:
+ def unpack_uint(self):
+ i = self.pos
+ self.pos = j = i+4
+ return struct.unpack('i', self.buf[i:j])
+
+ def unpack_int(self):
+ x = self.unpack_uint()
+ if x >= 0x80000000L: x = x - 0x100000000L
+ return int(x)
+
+ unpack_enum = unpack_int
+
+ unpack_bool = unpack_int
+
+ def unpack_uhyper(self):
+ hi = self.unpack_uint()
+ lo = self.unpack_uint()
+ return long(hi)<<32 | lo
+
+ def unpack_hyper(self):
+ x = self.unpack_uhyper()
+ if x >= 0x8000000000000000L: x = x - 0x10000000000000000L
+ return x
+
+ def unpack_fstring(self, n):
+ if n < 0:
+ raise ValueError, 'fstring size must be nonnegative'
+ i = self.pos
+ j = i + (n+3)/4*4
+ if j > len(self.buf):
+ raise RuntimeError, 'buffer overrun'
+ self.pos = j
+ return self.buf[i:i+n]
+
+ unpack_fopaque = unpack_fstring
+
+ def unpack_string(self):
+ n = self.unpack_uint()
+ return self.unpack_fstring(n)
+
+ unpack_opaque = unpack_string
+
+ def unpack_list(self, unpack_item):
+ list = []
+ while 1:
+ x = self.unpack_uint()
+ if not x: break
+ if x <> 1:
+ raise RuntimeError, \
+ '0 or 1 expected, got ' + `x`
+ list.append(unpack_item())
+ return list