Mercurial > ~darius > hgwebdir.cgi > pyinst
view rpc.py @ 71:00800345fbae
Python3ise RSIB code
author | Daniel O'Connor <doconnor@gsoft.com.au> |
---|---|
date | Thu, 24 Aug 2023 16:52:10 +0930 |
parents | 91b476ebc0f2 |
children |
line wrap: on
line source
"A an RPC module, with optimizations for VXI-11 rpc calls" _rcsid="$Id: rpc.py 323 2011-04-06 19:10:03Z marcus $" #this module is 99% from the python distribution, Demo/rpc/rpc.py, with a few modifications #by Marcus Mendenhall to improve timeout handling, etc. It probably should follow any licensing #intent of whoever originated it. # Sun RPC version 2 -- RFC1057. # XXX There should be separate exceptions for the various reasons why # XXX an RPC can fail, rather than using RuntimeError for everything # 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 # Now there is, on receives. 2003.02.20 Marcus Mendenhall, Vanderbilt University marcus.h.mendenhall@vanderbilt.edu import xdrlib as xdr import socket import os from exceptions import * 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 # Exceptions BadRPCFormat = 'rpc.BadRPCFormat' BadRPCVersion = 'rpc.BadRPCVersion' GarbageArgs = 'rpc.GarbageArgs' class Unpacker(xdr.Unpacker): def unpack_auth(self): flavor = self.unpack_enum() stuff = self.unpack_opaque() return (flavor, stuff) def unpack_callheader(self): xid = self.unpack_uint(xid) temp = self.unpack_enum() if temp != CALL: raise BadRPCFormat('no CALL but ' + repr(temp)) temp = self.unpack_uint() if temp != RPCVERSION: raise BadRPCVerspion('bad RPC version ' + repr(temp)) prog = self.unpack_uint() vers = self.unpack_uint() proc = self.unpack_uint() cred = self.unpack_auth() verf = self.unpack_auth() return xid, prog, vers, proc, cred, verf # Caller must add procedure-specific part of call def unpack_replyheader(self): xid = self.unpack_uint() mtype = self.unpack_enum() if mtype != REPLY: raise RuntimeError('no REPLY but ' + repr(mtype)) stat = self.unpack_enum() if stat == MSG_DENIED: stat = self.unpack_enum() if stat == RPC_MISMATCH: low = self.unpack_uint() high = self.unpack_uint() raise RuntimeError('MSG_DENIED: RPC_MISMATCH: ' + repr((low, high))) if stat == AUTH_ERROR: stat = self.unpack_uint() raise RuntimeError('MSG_DENIED: AUTH_ERROR: ' + repr(stat)) raise RuntimeError('MSG_DENIED: ' + repr(stat)) if stat != MSG_ACCEPTED: raise RuntimeError('Neither MSG_DENIED nor MSG_ACCEPTED: ' + repr(stat)) verf = self.unpack_auth() stat = self.unpack_enum() if stat == PROG_UNAVAIL: raise RuntimeError('call failed: PROG_UNAVAIL') if stat == PROG_MISMATCH: low = self.unpack_uint() high = self.unpack_uint() raise RuntimeError('call failed: PROG_MISMATCH: ' + repr((low, high))) if stat == PROC_UNAVAIL: raise RuntimeError('call failed: PROC_UNAVAIL') if stat == GARBAGE_ARGS: raise RuntimeError('call failed: GARBAGE_ARGS') if stat != SUCCESS: raise RuntimeError('call failed: ' + repr(stat)) return xid, verf # Caller must get procedure-specific part of reply # Subroutines to create opaque authentication objects def make_auth_null(): return '' def make_auth_unix(seed, host, uid, gid, groups): p = Packer() p.pack_auth_unix(seed, host, uid, gid, groups) return p.get_buf() def make_auth_unix_default(): try: from os import getuid, getgid uid = getuid() gid = getgid() except ImportError: uid = gid = 0 import time return make_auth_unix(int(time.time()-unix_epoch()), \ socket.gethostname(), uid, gid, []) _unix_epoch = -1 def unix_epoch(): """Very painful calculation of when the Unix Epoch is. This is defined as the return value of time.time() on Jan 1st, 1970, 00:00:00 GMT. On a Unix system, this should always return 0.0. On a Mac, the calculations are needed -- and hard because of integer overflow and other limitations. """ global _unix_epoch if _unix_epoch >= 0: return _unix_epoch import time now = time.time() localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...) gmt = time.gmtime(now) offset = time.mktime(localt) - time.mktime(gmt) y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0 offset, ss = divmod(ss + offset, 60) offset, mm = divmod(mm + offset, 60) offset, hh = divmod(hh + offset, 24) d = d + offset _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0)) print("Unix epoch:", time.ctime(_unix_epoch)) return _unix_epoch # Common base class for clients class Client: def __init__(self, host, prog, vers, port): self.host = host self.prog = prog self.vers = vers self.port = port self.makesocket() # Assigns to self.sock self.bindsocket() self.connsocket() self.lastxid = 0 # XXX should be more random? self.addpackers() self.cred = None self.verf = None def close(self): self.sock.close() def makesocket(self): # This MUST be overridden raise RuntimeError('makesocket not defined') def connsocket(self): # Override this if you don't want/need a connection self.sock.connect((self.host, self.port)) 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() self.unpacker = Unpacker('') def make_call(self, proc, args, pack_func, unpack_func): #print "make_call() args = " + str(args) # Don't normally override this (but see Broadcast) if pack_func is None and args is not None: raise TypeError('non-null args with null pack_func') #print "packed args" self.start_call(proc) if pack_func: pack_func(args) self.do_call() if unpack_func: result = unpack_func() else: result = None #print "result = " + str(result) self.unpacker.done() return result 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): # This MUST be overridden raise RuntimeError('do_call not defined') 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): # Override this to use a more powerful verifier if self.verf == None: self.verf = (AUTH_NULL, make_auth_null()) return self.verf def call_0(self): # Procedure 0 is always like this return self.make_call(0, None, None, None) # Record-Marking standard support try: from select import select as _select except: _select=None def sendfrag_with_timeout(sock, last, frag, timeout_seconds=None): x = len(frag) if last: x = x | 0x80000000 header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff))) block=header+frag n=len(block) nsent=0 while(nsent<n): if _select and timeout_seconds: rlist, wlist, xlist=_select([],[sock],[], timeout_seconds) if not wlist: raise EOFError("Blocked write in sendfrag()") nsent+=sock.send(block[nsent:]) def recvfrag_with_timeout(sock, timeout_seconds=None): #print "receiving from ", sock if _select and timeout_seconds: #print "Selecting with timeout...", timeout_seconds rlist, wlist, xlist=_select([sock],[],[], timeout_seconds) if not rlist: raise EOFError("No header at all in recvfrag()") header = sock.recv(4) if len(header) < 4: raise EOFError x = int(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(len(frag) < n): if _select and timeout_seconds: #print "Selecting with timeout...", timeout_seconds rlist, wlist, xlist=_select([sock],[],[], timeout_seconds) if not rlist: raise EOFError("No data after header in recvfrag()") frag += sock.recv(n-len(frag)) return last, frag def recvrecord(sock, timeout_seconds=None): record = '' last = 0 while not last: last, frag = recvfrag_with_timeout(sock, timeout_seconds) record = record + frag return record def sendrecord(sock, record, timeout_seconds=None): sendfrag_with_timeout(sock, 1, record, timeout_seconds) # 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 list(range(last_resv_port_tried, LAST)) + \ list(range(FIRST, last_resv_port_tried)): last_resv_port_tried = i try: sock.bind((host, i)) return last_resv_port_tried except socket.error as xxx_todo_changeme: (errno, msg) = xxx_todo_changeme.args if errno != 114: raise socket.error(errno, msg) raise RuntimeError('can\'t assign reserved port') # Client using TCP to a specific port class RawTCPClient(Client): select_timeout_seconds=None def makesocket(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) def do_call(self): call = self.packer.get_buf() sendrecord(self.sock, call, self.select_timeout_seconds) reply = recvrecord(self.sock, self.select_timeout_seconds) 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 ' + repr(xid) + \ ' instead of ' + repr(self.lastxid)) # Client using UDP to a specific port class RawUDPClient(Client): def makesocket(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) def do_call(self): call = self.packer.get_buf() self.sock.send(call) try: from select import select except ImportError: print('WARNING: select not found, RPC may hang') select = None BUFSIZE = 8192 # Max UDP buffer size timeout = 1 count = 5 while 1: r, w, x = [self.sock], [], [] if select: r, w, x = select(r, w, x, timeout) if self.sock not in r: count = count - 1 if count < 0: raise RuntimeError('timeout') if timeout < 25: timeout = timeout *2 ## print 'RESEND', timeout, count self.sock.send(call) continue reply = self.sock.recv(BUFSIZE) u = self.unpacker u.reset(reply) xid, verf = u.unpack_replyheader() if xid != self.lastxid: ## print 'BAD xid' continue break # Client using UDP broadcast to a specific port class RawBroadcastUDPClient(RawUDPClient): def __init__(self, bcastaddr, prog, vers, port): RawUDPClient.__init__(self, bcastaddr, prog, vers, port) self.reply_handler = None self.timeout = 30 def connsocket(self): # Don't connect -- use sendto self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) def set_reply_handler(self, reply_handler): self.reply_handler = reply_handler def set_timeout(self, timeout): self.timeout = timeout # Use None for infinite timeout def make_call(self, proc, args, pack_func, unpack_func): if pack_func is None and args is not None: raise TypeError('non-null args with null pack_func') self.start_call(proc) if pack_func: pack_func(args) call = self.packer.get_buf() self.sock.sendto(call, (self.host, self.port)) try: from select import select except ImportError: print('WARNING: select not found, broadcast will hang') select = None BUFSIZE = 8192 # Max UDP buffer size (for reply) replies = [] if unpack_func is None: def dummy(): pass unpack_func = dummy while 1: r, w, x = [self.sock], [], [] if select: if self.timeout is None: r, w, x = select(r, w, x) else: r, w, x = select(r, w, x, self.timeout) if self.sock not in r: break reply, fromaddr = self.sock.recvfrom(BUFSIZE) u = self.unpacker u.reset(reply) xid, verf = u.unpack_replyheader() if xid != self.lastxid: ## print 'BAD xid' continue reply = unpack_func() self.unpacker.done() replies.append((reply, fromaddr)) if self.reply_handler: self.reply_handler(reply, fromaddr) return replies # Port mapper interface # 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 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) def pack_call_args(self, ca): prog, vers, proc, args = ca self.pack_uint(prog) self.pack_uint(vers) self.pack_uint(proc) self.pack_opaque(args) 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) def unpack_call_result(self): port = self.unpack_uint() res = self.unpack_opaque() return port, res class PartialPortMapperClient: def addpackers(self): self.packer = PortMapperPacker() self.unpacker = PortMapperUnpacker('') def Set(self, mapping): return self.make_call(PMAPPROC_SET, mapping, \ self.packer.pack_mapping, \ self.unpacker.unpack_uint) def Unset(self, mapping): return self.make_call(PMAPPROC_UNSET, mapping, \ self.packer.pack_mapping, \ self.unpacker.unpack_uint) def Getport(self, mapping): return self.make_call(PMAPPROC_GETPORT, mapping, \ self.packer.pack_mapping, \ self.unpacker.unpack_uint) def Dump(self): return self.make_call(PMAPPROC_DUMP, None, \ None, \ self.unpacker.unpack_pmaplist) def Callit(self, ca): return self.make_call(PMAPPROC_CALLIT, ca, \ self.packer.pack_call_args, \ self.unpacker.unpack_call_result) class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient): def __init__(self, host, port=PMAP_PORT, timeout_seconds=None): RawTCPClient.__init__(self, \ host, PMAP_PROG, PMAP_VERS, port) self.select_timeout_seconds=timeout_seconds class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient): def __init__(self, host, port=PMAP_PORT): RawUDPClient.__init__(self, \ host, PMAP_PROG, PMAP_VERS, port) class BroadcastUDPPortMapperClient(PartialPortMapperClient, \ RawBroadcastUDPClient): def __init__(self, bcastaddr): RawBroadcastUDPClient.__init__(self, \ bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT) # Generic clients that find their server through the Port mapper class TCPClient(RawTCPClient): def __init__(self, host, prog, vers, portmap_proxy_host=None, portmap_proxy_port=PMAP_PORT, timeout_seconds=None): self.select_timeout_seconds=timeout_seconds if portmap_proxy_host is None: portmap_proxy_host=host #use a proxy to get around firewalled portmappers pmap = TCPPortMapperClient(portmap_proxy_host, portmap_proxy_port,timeout_seconds) port = pmap.Getport((prog, vers, IPPROTO_TCP, 0)) pmap.close() if port == 0: raise RuntimeError('program not registered') RawTCPClient.__init__(self, host, prog, vers, port) class UDPClient(RawUDPClient): def __init__(self, host, prog, vers, portmap_proxy_host=None, portmap_proxy_port=PMAP_PORT): if portmap_proxy_host is None: portmap_proxy_host=host #use a proxy to get around firewalled portmappers pmap = UDPPortMapperClient(portmap_proxy_host, portmap_proxy_port) port = pmap.Getport((prog, vers, IPPROTO_UDP, 0)) pmap.close() if port == 0: raise RuntimeError('program not registered') RawUDPClient.__init__(self, host, prog, vers, port) class BroadcastUDPClient(Client): def __init__(self, bcastaddr, prog, vers): self.pmap = BroadcastUDPPortMapperClient(bcastaddr) self.pmap.set_reply_handler(self.my_reply_handler) self.prog = prog self.vers = vers self.user_reply_handler = None self.addpackers() def close(self): self.pmap.close() def set_reply_handler(self, reply_handler): self.user_reply_handler = reply_handler def set_timeout(self, timeout): self.pmap.set_timeout(timeout) def my_reply_handler(self, reply, fromaddr): port, res = reply self.unpacker.reset(res) result = self.unpack_func() self.unpacker.done() self.replies.append((result, fromaddr)) if self.user_reply_handler is not None: self.user_reply_handler(result, fromaddr) def make_call(self, proc, args, pack_func, unpack_func): self.packer.reset() if pack_func: pack_func(args) if unpack_func is None: def dummy(): pass self.unpack_func = dummy else: self.unpack_func = unpack_func self.replies = [] packed_args = self.packer.get_buf() dummy_replies = self.pmap.Callit( \ (self.prog, self.vers, proc, packed_args)) return self.replies # 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): 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.makesocket() # Assigns to self.sock and self.prot self.bindsocket() self.host, self.port = self.sock.getsockname() self.addpackers() def handle(self, call): # Don't use unpack_header but parse the header piecewise # XXX I have no idea if I am using the right error responses! self.unpacker.reset(call) self.packer.reset() xid = self.unpacker.unpack_uint() self.packer.pack_uint(xid) temp = self.unpacker.unpack_enum() if temp != CALL: return None # Not worthy of a reply self.packer.pack_uint(REPLY) temp = self.unpacker.unpack_uint() if temp != RPCVERSION: self.packer.pack_uint(MSG_DENIED) self.packer.pack_uint(RPC_MISMATCH) self.packer.pack_uint(RPCVERSION) self.packer.pack_uint(RPCVERSION) return self.packer.get_buf() self.packer.pack_uint(MSG_ACCEPTED) self.packer.pack_auth((AUTH_NULL, make_auth_null())) prog = self.unpacker.unpack_uint() if prog != self.prog: self.packer.pack_uint(PROG_UNAVAIL) return self.packer.get_buf() vers = self.unpacker.unpack_uint() if vers != self.vers: self.packer.pack_uint(PROG_MISMATCH) self.packer.pack_uint(self.vers) self.packer.pack_uint(self.vers) return self.packer.get_buf() proc = self.unpacker.unpack_uint() methname = 'handle_' + repr(proc) try: meth = getattr(self, methname) except AttributeError: self.packer.pack_uint(PROC_UNAVAIL) return self.packer.get_buf() cred = self.unpacker.unpack_auth() verf = self.unpacker.unpack_auth() try: meth() # Unpack args, call turn_around(), pack reply except (EOFError, GarbageArgs): # Too few or too many arguments self.packer.reset() self.packer.pack_uint(xid) self.packer.pack_uint(REPLY) self.packer.pack_uint(MSG_ACCEPTED) self.packer.pack_auth((AUTH_NULL, make_auth_null())) self.packer.pack_uint(GARBAGE_ARGS) return self.packer.get_buf() def turn_around(self): try: self.unpacker.done() except RuntimeError: raise GarbageArgs self.packer.pack_uint(SUCCESS) def handle_0(self): # Handle NULL message self.turn_around() 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() self.unpacker = Unpacker('') class TCPServer(Server): def register(self): mapping = self.prog, self.vers, self.prot, self.port p = TCPPortMapperClient(self.host) if not p.Set(mapping): raise RuntimeError('register failed') def unregister(self): mapping = self.prog, self.vers, self.prot, self.port p = TCPPortMapperClient(self.host) if not p.Unset(mapping): raise RuntimeError('unregister failed') def makesocket(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.prot = IPPROTO_TCP def loop(self): self.sock.listen(0) while 1: self.session(self.sock.accept()) def session(self, connection): sock, (host, port) = connection while 1: try: call = recvrecord(sock) except EOFError: break except socket.error as msg: print('socket error:', msg) break reply = self.handle(call) if reply is not None: sendrecord(sock, reply) def forkingloop(self): # Like loop but uses forksession() self.sock.listen(0) while 1: self.forksession(self.sock.accept()) def forksession(self, connection): # Like session but forks off a subprocess import os # Wait for deceased children try: while 1: pid, sts = os.waitpid(0, 1) except os.error: pass pid = None try: pid = os.fork() if pid: # Parent connection[0].close() return # Child self.session(connection) finally: # Make sure we don't fall through in the parent if pid == 0: os._exit(0) class UDPServer(Server): def register(self): mapping = self.prog, self.vers, self.prot, self.port p = UDPPortMapperClient(self.host) if not p.Set(mapping): raise RuntimeError('register failed') def unregister(self): mapping = self.prog, self.vers, self.prot, self.port p = UDPPortMapperClient(self.host) if not p.Unset(mapping): raise RuntimeError('unregister failed') def makesocket(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.prot = IPPROTO_UDP def loop(self): while 1: self.session() def session(self): call, host_port = self.sock.recvfrom(8192) reply = self.handle(call) if reply != None: self.sock.sendto(reply, host_port) # Simple test program -- dump local portmapper status def test(): pmap = UDPPortMapperClient('') list = pmap.Dump() list.sort() for prog, vers, prot, port in list: print(prog, vers, end=' ') if prot == IPPROTO_TCP: print('tcp', end=' ') elif prot == IPPROTO_UDP: print('udp', end=' ') else: print(prot, end=' ') print(port) # Test program for broadcast operation -- dump everybody's portmapper status def testbcast(): import sys if sys.argv[1:]: bcastaddr = sys.argv[1] else: bcastaddr = '<broadcast>' def rh(reply, fromaddr): host, port = fromaddr print(host + '\t' + repr(reply)) pmap = BroadcastUDPPortMapperClient(bcastaddr) pmap.set_reply_handler(rh) pmap.set_timeout(5) replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0)) # Test program for server, with corresponding client # On machine A: python -c 'import rpc; rpc.testsvr()' # On machine B: python -c 'import rpc; rpc.testclt()' A # (A may be == B) def testsvr(): # Simple test class -- proc 1 doubles its string argument as reply class S(UDPServer): def handle_1(self): arg = self.unpacker.unpack_string() self.turn_around() print('RPC function 1 called, arg', repr(arg)) self.packer.pack_string(arg + arg) # s = S('', 0x20000000, 1, 0) try: s.unregister() except RuntimeError as msg: print('RuntimeError:', msg, '(ignored)') s.register() print('Service started...') try: s.loop() finally: s.unregister() print('Service interrupted.') def testclt(): import sys if sys.argv[1:]: host = sys.argv[1] else: host = '' # Client for above server class C(UDPClient): def call_1(self, arg): return self.make_call(1, arg, \ self.packer.pack_string, \ self.unpacker.unpack_string) c = C(host, 0x20000000, 1) print('making call...') reply = c.call_1('hello, world, ') print('call returned', repr(reply)) def testclt2(): import sys host = '127.0.0.1' # Client for above server class C(UDPClient): def call_1(self, arg): return self.make_call(1, arg, \ self.packer.pack_string, \ self.unpacker.unpack_string) c = C(host, 0x20000000, 1) print('making call...') reply = c.call_1('hello, world, ') print('call returned', repr(reply))