9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
From: "Russ Cox" <rsc@plan9.bell-labs.com>
To: 9fans@cse.psu.edu
Subject: Re: [9fans] Serving 9p in python - anyone started that?
Date: Wed, 13 Nov 2002 14:18:51 -0500	[thread overview]
Message-ID: <cbe90192194055d2b334055aab40baeb@plan9.bell-labs.com> (raw)

yep.  here's a minimal 9p2000 test scaffolding.
it predates the python dial, hence the weird exec of aux/trampoline
in connetwork.

all i wrote was version testing.  but the fcall module
is complete.  and the arg parser is nice.



# To unbundle, run this file
echo 9ptest
sed 's/.//' >9ptest <<'//GO.SYSIN DD 9ptest'
-#!/bin/python
-
-from arg import ArgParser
-from fcall import *
-from plan9 import *
-from plan9 import _exec
-import plan9, sys
-
-t,r = None, None
-fd = None
-Tag = 1
-chatty = 0
-
-def chat(s):
-	if chatty:
-		sys.stderr.write(s+'\n')
-		sys.stderr.flush()
-
-def conservice(name):
-	return plan9.open(name, plan9.ORDWR)
-
-def connetwork(addr):
-	return concommand('aux/trampoline '+addr)
-
-def concommand(cmd):
-	p = pipe()
-	pid = rfork(RFFDG|RFPROC|RFNOWAIT)
-	if pid == 0:
-		try:
-			close(p[0])
-			dup(p[1], 0)
-			dup(p[1], 1)
-			_exec('/bin/rc', ['rc', '-c', cmd])
-		except Exception, msg:
-			sys.stderr.write('cmd exec: '+str(msg)+'\n')
-			sys.stderr.flush()
-			sys.exit(1)
-	else:
-		close(p[1])
-		return p[0]
-
-def tx(_t):
-	global t, r
-	t = _t
-	pkt = t.unload()
-	chat('-> %s' % (t,))
-	n = write(fd, pkt)
-	try:
-		pkt = read9pmsg(fd)
-		r = Fcall()
-		r.load(pkt)
-	except Exception, e:
-		sys.stdout.write('sent: '+str(t)+'\n')
-		sys.stdout.write('error receiving response: '+str(e)+'\n')
-#		sys.exit(1)
-		raise
-	chat('<- %s' % (r,))
-	return r
-
-def note(s):
-	sys.stdout.write('sent: '+str(t)+'\n')
-	sys.stdout.write('recv: '+str(r)+'\n')
-	sys.stdout.write(s+'\n')
-	sys.stdout.flush()
-
-def testversion():
-	r = tx(mkfcall(Tflush, Tag, 42))
-	if r.type != Terror:
-		note('server should reject messages before first Tversion is sent')
-
-	# test various msizes and versions
-	def test(msize, vers, expectvers='9P2000'):
-		r = tx(mkfcall(Tversion, Tag, msize, vers))
-		if r.type != Rversion:
-			note('response to Tversion should always be Rversion')
-			return
-		if r.msize > msize:
-			note('response msize must be <= request msize')
-		if r.version != expectvers:
-			note('response version must be '+expectvers)
-
-	test(8192+IOHDRSZ, '9P2000')	# common case
-	test(512, '9P2000')	# small msize
-	test(8192+IOHDRSZ, '9P2005')	# future protocol
-	test(16384, '9P2000')	# large msize
-	test(8192+IOHDRSZ, '9P2000.1') # subprotocol
-	test(8192+IOHDRSZ, '9P2001.2') # future subprotocol
-	test(8192+IOHDRSZ, '8P2000', 'unknown')
-
-def main():
-	global fd, chatty
-	arg = ArgParser('usage: 9ptest [-c|-n] service\n')
-	con = conservice
-	for o in arg:
-		if o=='-c':
-			con = concommand
-		elif o=='-n':
-			con = connetwork
-		elif o=='-v':
-			chatty += 1
-		else:
-			arg.error('unknown option '+o)
-	if len(arg.argv) != 1:
-		arg.error()
-
-	fd = con(arg.argv[0])
-
-	testversion()
-
-
-if __name__=='__main__':
-	main()
//GO.SYSIN DD 9ptest
echo fcall.py
sed 's/.//' >fcall.py <<'//GO.SYSIN DD fcall.py'
-"""Pack and unpack 9P2000 messages."""
-
-from __future__ import nested_scopes, generators
-import sys, struct
-
-class FcallError(Exception):
-	def __init__(self, msg=None):
-		if msg:
-			self.msg = msg
-
-IOHDRSZ = 24
-
-Tversion, \
-Rversion, \
-Tauth, \
-Rauth, \
-Tattach, \
-Rattach, \
-Terror, \
-Rerror, \
-Tflush, \
-Rflush, \
-Twalk, \
-Rwalk, \
-Topen, \
-Ropen, \
-Tcreate, \
-Rcreate, \
-Tread, \
-Rread, \
-Twrite, \
-Rwrite, \
-Tclunk, \
-Rclunk, \
-Tremove, \
-Rremove, \
-Tstat, \
-Rstat, \
-Twstat, \
-Rwstat = range(100, 128)
-
-fcalls = {
-	Tversion: ('LS', ['msize', 'version']),
-	Rversion: ('LS', ['msize', 'version']),
-
-	Tauth: ('LSS', ['afid', 'uname', 'aname']),
-	Rauth: ('q', ['aqid']),
-
-	Rerror: ('S', ['ename']),
-
-	Tflush: ('H', ['oldtag']),
-	Rflush: ('', []),
-
-	Tattach: ('LLSS', ['fid', 'afid', 'uname', 'aname']),
-	Rattach: ('Q', ['qid']),
-
-	Twalk: ('FF#S', ['fid', 'newfid', 'wname']),
-	Rwalk: ('#Q', ['qid']),
-
-	Topen: ('LB', ['fid', 'mode']),
-	Ropen: ('qL', ['qid', 'iounit']),
-
-	Tcreate: ('LSLB', ['fid', 'name', 'perm', 'mode']),
-	Rcreate: ('qL', ['qid', 'iounit']),
-
-	Tread: ('LQL', ['fid', 'offset', 'count']),
-	Rread: ('D', ['data']),
-
-	Twrite: ('LQD', ['fid', 'offset', 'data']),
-	Rwrite: ('L', ['count']),
-
-	Tclunk: ('L', ['fid']),
-	Rclunk: ('', []),
-
-	Tremove: ('L', ['fid']),
-	Rremove: ('', []),
-
-	Tstat: ('L', ['fid']),
-	Rstat: ('D', ['stat']),
-
-	Twstat: ('LD', ['fid', 'stat']),
-	Rwstat: ('', [])
-}
-
-fcallnames = {
-	Tversion: 'Tversion',
-	Rversion: 'Rversion',
-
-	Tauth: 'Tauth',
-	Rauth: 'Rauth',
-
-	Rerror: 'Rerror',
-
-	Tflush: 'Tflush',
-	Rflush: 'Rflush',
-
-	Tattach: 'Tattach',
-	Rattach: 'Rattach',
-
-	Twalk: 'Twalk',
-	Rwalk: 'Rwalk',
-
-	Topen: 'Topen',
-	Ropen: 'Ropen',
-
-	Tcreate: 'Tcreate',
-	Rcreate: 'Rcreate',
-
-	Tread: 'Tread',
-	Rread: 'Rread',
-
-	Twrite: 'Twrite',
-	Rwrite: 'Rwrite',
-
-	Tclunk: 'Tclunk',
-	Rclunk: 'Rclunk',
-
-	Tremove: 'Tremove',
-	Rremove: 'Rremove',
-
-	Tstat: 'Tstat',
-	Rstat: 'Rstat',
-
-	Twstat: 'Twstat',
-	Rwstat: 'Rwstat',
-}
-
-def pack(fmt, vals):
-	pkt = ''
-	while fmt:
-		c = fmt[0]
-		fmt = fmt[1:]
-		v = vals[0]
-		vals = vals[1:]
-		if c in 'BHLQ':
-			pkt += struct.pack(c, v)
-		elif c == 'S':
-			pkt += pack('H', (len(v),))
-			pkt += v
-		elif c == 'q':
-			pkt += pack('VLB', v.path, v.vers, v.type)
-		elif c == 'D':
-			pkt += pack('L', (len(v),))
-			pkt += v
-		elif c == '#':
-			c = fmt[0]
-			fmt = fmt[1:]
-			pkt += pack(c*len(v), v)
-		else:
-			raise Exception('unknown format character \''+c+'\'')
-	return pkt
-
-def unpack(fmt, pkt):
-	l = []
-	while fmt:
-		c = fmt[0]
-		fmt = fmt[1:]
-		if c == 'B':
-			v, = struct.unpack('<B', pkt[:1])
-			pkt = pkt[1:]
-		elif c == 'H':
-			v, = struct.unpack('<H', pkt[:2])
-			pkt = pkt[2:]
-		elif c == 'L':
-			v, = struct.unpack('<L', pkt[:4])
-			pkt = pkt[4:]
-		elif c == 'Q':
-			v, = struct.unpack('<Q', pkt[:8])
-			pkt = pkt[8:]
-		elif c == 'S':
-			n, = struct.unpack('<H', pkt[:2])
-			v = pkt[2:2+n]
-			pkt = pkt[2+n:]
-		elif c == 'q':
-			q, pkt = unpack('VLB', pkt[:8+4+1])
-			v = plan9.Qid().fromtuple(q)
-		elif c == 'D':
-			n, = struct.unpack('<L', pkt[:4])
-			v = pkt[4:4+n]
-			pkt = pkt[4+n:]
-		elif c == '#':
-			n, = struct.unpack('<H', pkt[:2])
-			c = fmt[0]
-			fmt = fmt[1:]
-			v, pkt = unpack(c*n, pkt[2:])
-		else:
-			raise Exception('unknown format character \''+c+'\'')
-		l.append(v)
-	return l, pkt
-
-def mkfcall(*args):
-	f = Fcall()
-	f.loadtuple(*args)
-	return f
-
-class Fcall:
-	def __init__(self, type=None, args=None):
-		if type==None:
-			return
-		if not fcalls.has_key(type):
-			raise Exception('bad fcall type')
-		self.type = type
-		if args != None:
-			self.fromtuple(args)
-		return
-
-	def loadtuple(self, *args):
-		self.type = args[0]
-		self.tag = args[1]
-		names = fcalls[self.type][1]
-		off = 2
-		for n in names:
-			self.__dict__[n] = args[off]
-			off += 1
-		return self
-
-	def load(self, pkt):
-		(l, self.type, self.tag), npkt = unpack('LBH', pkt)
-		if l != len(pkt):
-			raise Exception('packet length field is a lie')
-		pkt = npkt
-		if not fcalls.has_key(self.type):
-			raise Exception('bad packet type %d' % (self.type,))
-		fmt, names = fcalls[self.type]
-		vals, pkt = unpack(fmt, pkt)
-		if pkt:
-			raise Exception('packet too large')
-		for n,v in zip(names, vals):
-			self.__dict__[n] = v
-		return self
-
-	def unload(self):
-		hdr = pack('BH', (self.type, self.tag))
-		fmt, names = fcalls[self.type]
-		dat = pack(fmt, map(lambda x: self.__dict__[x], names))
-		l = pack('L', (4+len(hdr)+len(dat),))
-		return l+hdr+dat
-
-	def __repr__(self):
-		try:
-			s = fcallnames[self.type]
-			for n in fcalls[self.type][1]:
-				s += ' '+str(self.__dict__[n])
-			return s
-		except Exception:
-			return '<malformed or uninitialized Fcall>'
-
//GO.SYSIN DD fcall.py
echo arg.py
sed 's/.//' >arg.py <<'//GO.SYSIN DD arg.py'
-from __future__ import generators
-import sys, copy
-
-"""Simple command-line argument iterator.
-
-A typical example looks like:
-
-	arg = ArgParser('usage: example [-d] [-r root] database\n')
-	for o in arg:
-		if o=='-d':
-			debug=1
-		elif o=='-r':
-			root = arg.nextarg()
-		else:
-			arg.error('unknown option '+o)
-	if len(arg.argv) != 1:
-		arg.error()
-
-This illustrates all the important points:
-
-	* arg is a generator that returns the next argument.
-	  >>>The behavior of the generator depends on the behavior
-	  of the body of your for loop.<<<  This is why you don't have
-	  to tell the ArgParser about your options a priori.  If an option
-	  has an argument, you call arg.nextarg() to fetch it.  (If you
-	  want an option to have two arguments, call arg.nextarg twice.)
-
-	 * After the loop has finished, arg.argv contains the
-	  remaining command-line arguments.
-
-	 * Calling arg.error prints the optional passed string,
-	  then prints the usage message, then exits.
-
-A few other points:
-
-	* Consistent with typical Unix conventions, option parsing ends
-	  after seeing '--', before seeing '-', or before any command-line argument
-	  not beginning with a - (that wasn't gobbled as an option argument).
-	  Assuming that -c does not take an argument but -f does, the following
-	  set of command lines and parsings illustrates the rules:
-		foo -c -- -a
-			opts: -c
-			args: -a
-		foo -c - -a
-			opts: -c
-			args: - -a
-		foo -c bar baz -a
-			opts: -c
-			args: bar baz -a
-		foo -cfbar baz -a
-			opts: -c -f
-				(-f took bar)
-			args: baz -a
-		foo -cf bar baz -a
-			opts: -c -f
-				(-f took bar)
-			args: baz -a
-		foo -fc bar baz -a
-			opts: -f
-				(-f took c)
-			args: bar baz -a
-
-	* Single character short options begin with - and take arguments from the
-	  rest of the current argument or from the next argument.  For example,
-	  	foo -cbar
-	  	foo -c bar
-	  are equivalent.  There is no support for optional arguments, since that
-	  introduces command-line parsing ambiguities.
-
-	* Long options begin with -- and take arguments from an optional
-	  ``=ARG'' suffix.  For example,
-	  	foo --long=bar
-	  is the only way to specify an argument to the --long option.
-	  If the handler for '--long' does not fetch the argument with arg.nextarg,
-	  the parser will call arg.error automatically.  There is support for optional
-	  arguments to long options, since that does not introduce any ambiguities.
-	  To fetch an optional argument call arg.nextarg(allownone=1).  If there
-	  is no argument, None will be returned.
-
-"""
-
-class ArgError(Exception):
-	def __init__(self, msg=None):
-		if msg:
-			self.msg = msg
-
-class ArgParser:
-	def __init__(self, usage, argv=sys.argv):
-		self.argv0 = argv[0]
-		self.argv = argv[1:]
-		self.usage = usage
-		self.waitingarg = ''
-
-	def __iter__(self):
-		# this assumes the "
-		while self.argv:
-			if self.argv[0]=='-' or self.argv[0][0]!='-':
-				break
-			a = self.argv.pop(0)
-			if a=='--':
-				break
-			if a[0:2]=='--':
-				i = a.find('=')
-				if i==-1:
-					self.waitingarg=None
-					self.option = a
-					yield self.option
-					self.option = None
-				else:
-					self.waitingarg = a[i+1:]
-					self.option = a[0:i]
-					yield self.option
-					if self.waitingarg:		# wasn't fetched using optarg
-						self.error(self.option+' does not take an argument')
-					self.option = None
-				continue
-			self.waitingarg = a[1:]
-			while self.waitingarg:
-				a = self.waitingarg[0:1]
-				self.waitingarg = self.waitingarg[1:]
-				self.option = '-'+a
-				yield self.option
-				self.option = None
-
-	def nextarg(self, allownone=0):
-		if self.waitingarg==None:
-			if allownone:
-				return None
-			self.error(self.option+' requires an argument')
-		elif self.waitingarg:
-			ret = self.waitingarg
-			self.waitingarg=''
-		else:
-			try:
-				ret = self.argv.pop(0)
-			except IndexError:
-				self.error(self.option+' requires an argument')
-		return ret
-
-	def error(self, msg=None):
-		if msg:
-			sys.stderr.write('argument error: '+msg+'\n')
-		sys.stderr.write(self.usage)
-		sys.stderr.flush()
-		sys.exit(1)
-
//GO.SYSIN DD arg.py



             reply	other threads:[~2002-11-13 19:18 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-11-13 19:18 Russ Cox [this message]
  -- strict thread matches above, loose matches on Subject: below --
2002-11-14 20:56 markp
2002-11-14 21:02 ` matt
2002-11-14 18:54 Russ Cox
2002-11-15 11:52 ` Boyd Roberts
     [not found] <rsc@plan9.bell-labs.com>
2002-11-14 17:33 ` Russ Cox
2002-11-14 18:28   ` Scott Schwartz
2002-11-14 18:46     ` matt
2002-11-14 19:19       ` Dan Cross
2002-11-14 19:00     ` William Josephson
2002-11-14  9:49 Fco.J.Ballesteros
2002-11-14 10:28 ` matt
2002-11-14  9:42 okamoto
2002-11-14  8:53 Russ Cox
2002-11-14 17:05 ` Ronald G. Minnich
2002-11-14 18:24   ` Scott Schwartz
2002-11-14  8:34 Fco.J.Ballesteros
2002-11-14 17:37 ` John E. Barham
2002-11-13 17:22 matt
2002-11-13 19:33 ` John E. Barham

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cbe90192194055d2b334055aab40baeb@plan9.bell-labs.com \
    --to=rsc@plan9.bell-labs.com \
    --cc=9fans@cse.psu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).