Documentation ¶
Overview ¶
Package styxproto provides low-level routines for parsing and producing 9P2000 messages.
The styxproto package is to be used for making higher-level 9P2000 libraries. The parsing routines within make very few assumptions or decisions, so that it may be used for a wide variety of higher-level packages. When decoding messages, memory usage is bounded using a fixed-size buffer. This allows servers using the styxproto package to have predictable resource usage based on the number of connections.
To minimize allocations, the styxproto package does not decode messages. Instead, messages are validated and wrapped with convenient accessor methods.
Index ¶
- Constants
- Variables
- func Write(w io.Writer, m Msg) (written int64, err error)
- type BadMessage
- type Decoder
- type Encoder
- func (enc *Encoder) Err() error
- func (enc *Encoder) Flush() error
- func (enc *Encoder) Rattach(tag uint16, qid Qid)
- func (enc *Encoder) Rauth(tag uint16, qid Qid)
- func (enc *Encoder) Rclunk(tag uint16)
- func (enc *Encoder) Rcreate(tag uint16, qid Qid, iounit uint32)
- func (enc *Encoder) Rerror(tag uint16, errfmt string, v ...interface{})
- func (enc *Encoder) Rflush(tag uint16)
- func (enc *Encoder) Ropen(tag uint16, qid Qid, iounit uint32)
- func (enc *Encoder) Rread(tag uint16, data []byte) (n int, err error)
- func (enc *Encoder) Rremove(tag uint16)
- func (enc *Encoder) Rstat(tag uint16, stat Stat)
- func (enc *Encoder) Rversion(msize uint32, version string)
- func (enc *Encoder) Rwalk(tag uint16, wqid ...Qid) error
- func (enc *Encoder) Rwrite(tag uint16, count int64)
- func (enc *Encoder) Rwstat(tag uint16)
- func (enc *Encoder) Tattach(tag uint16, fid, afid uint32, uname, aname string)
- func (enc *Encoder) Tauth(tag uint16, afid uint32, uname, aname string)
- func (enc *Encoder) Tclunk(tag uint16, fid uint32)
- func (enc *Encoder) Tcreate(tag uint16, fid uint32, name string, perm uint32, mode uint8)
- func (enc *Encoder) Tflush(tag, oldtag uint16)
- func (enc *Encoder) Topen(tag uint16, fid uint32, mode uint8)
- func (enc *Encoder) Tread(tag uint16, fid uint32, offset, count int64) error
- func (enc *Encoder) Tremove(tag uint16, fid uint32)
- func (enc *Encoder) Tstat(tag uint16, fid uint32)
- func (enc *Encoder) Tversion(msize uint32, version string)
- func (enc *Encoder) Twalk(tag uint16, fid, newfid uint32, wname ...string) error
- func (enc *Encoder) Twrite(tag uint16, fid uint32, offset int64, data []byte) (int, error)
- func (enc *Encoder) Twstat(tag uint16, fid uint32, stat Stat)
- type Msg
- type Qid
- type Rattach
- type Rauth
- type Rclunk
- type Rcreate
- type Rerror
- type Rflush
- type Ropen
- type Rread
- type Rremove
- type Rstat
- type Rversion
- type Rwalk
- type Rwrite
- type Rwstat
- type Stat
- func (s Stat) Atime() uint32
- func (s Stat) Dev() uint32
- func (s Stat) Gid() []byte
- func (s Stat) Length() int64
- func (s Stat) Mode() uint32
- func (s Stat) Mtime() uint32
- func (s Stat) Muid() []byte
- func (s Stat) Name() []byte
- func (s Stat) Qid() Qid
- func (s Stat) SetAtime(t uint32)
- func (s Stat) SetDev(d uint32)
- func (s Stat) SetLength(n int64)
- func (s Stat) SetMode(m uint32)
- func (s Stat) SetMtime(t uint32)
- func (s Stat) SetQid(q Qid)
- func (s Stat) SetType(t uint16)
- func (s Stat) String() string
- func (s Stat) Type() uint16
- func (s Stat) Uid() []byte
- type Tattach
- type Tauth
- type Tclunk
- type Tcreate
- type Tflush
- type Topen
- type Tread
- type Tremove
- type Tstat
- type Tversion
- type Twalk
- type Twrite
- type Twstat
Examples ¶
Constants ¶
const ( OREAD = 0 // open read-only OWRITE = 1 // open write-only ORDWR = 2 // open read-write OEXEC = 3 // execute (== read but check execute permission) OTRUNC = 16 // or'ed in (except for exec), truncate file first OCEXEC = 32 // or'ed in, close on exec ORCLOSE = 64 // or'ed in, remove on close )
Flags for the mode field in Topen and Tcreate messages
const ( DMDIR = 0x80000000 // mode bit for directories DMAPPEND = 0x40000000 // mode bit for append only files DMEXCL = 0x20000000 // mode bit for exclusive use files DMMOUNT = 0x10000000 // mode bit for mounted channel DMAUTH = 0x08000000 // mode bit for authentication file DMTMP = 0x04000000 // mode bit for non-backed-up file DMREAD = 0x4 // mode bit for read permission DMWRITE = 0x2 // mode bit for write permission DMEXEC = 0x1 // mode bit for execute permission // Mask for the type bits DMTYPE = DMDIR | DMAPPEND | DMEXCL | DMMOUNT | DMTMP // Mask for the permissions bits DMPERM = DMREAD | DMWRITE | DMEXEC )
File modes
const ( QTDIR = 0x80 // directories QTAPPEND = 0x40 // append only files QTEXCL = 0x20 // exclusive use files QTMOUNT = 0x10 // mounted channel QTAUTH = 0x08 // authentication file (afid) QTTMP = 0x04 // non-backed-up file QTFILE = 0x00 )
A Qid's type field represents the type of a file (directory, etc.), represented as a bit vector corresponding to the high 8 bits of the file's mode word.
const DefaultBufSize = 8192
DefaultBufSize is the default buffer size used in a Decoder
const DefaultMaxSize = 8 * megabyte
DefaultMaxSize is the default maximum size of a 9P message.
const IOHeaderSize = 4 + 1 + 2 + 4 + 8 + 4
IOHeaderSize is the length of all fixed-width fields in a Twrite or Tread message. Twrite and Tread messages are defined as
size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] size[4] Tread tag[2] fid[4] offset[8] count[4]
const MaxAttachLen = 255
MaxAttachLen is the maximum length (in bytes) of the aname field of Tattach and Tauth requests.
const MaxErrorLen = 512
MaxErrorLen is the maximum length (in bytes) of the Ename field in an Rerror message.
const MaxFileLen = 1<<63 - 1
MaxFileLen is the maximum length of a single file. While the 9P protocol supports files with a length of up to 8 EB (exabytes), to reduce the risk of overflow errors, the styxproto package only supports lengths of up to 4 EB so that it may fit within a signed 64-bit integer.
const MaxFilenameLen = 255
MaxFilenameLen is the maximum length of a file name in bytes
const MaxOffset = 1<<63 - 1
MaxOffset is the maximum value of the offset field in Tread and Twrite requests
const MaxStatLen = minStatLen + MaxFilenameLen + (MaxUidLen * 3)
MaxStatLen is the maximum size of a Stat structure.
const MaxUidLen = 45
MaxUidLen is the maximum length (in bytes) of a username or group identifier.
const MaxVersionLen = 20
MaxVersionLen is the maximum length of the protocol version string in bytes
const MaxWElem = 16
MaxWElem is the maximum allowed number of path elements in a Twalk request
const MinBufSize = MaxWElem*(MaxFilenameLen+2) + 13 + 4
MinBufSize is the minimum size (in bytes) of the internal buffers in a Decoder.
const NoFid = ^uint32(0)
NoFid is a reserved fid used in a Tattach request for the afid field, that indicates that the client does not wish to authenticate his session.
const NoTag = ^uint16(0)
NoTag is the tag for Tversion and Rversion requests.
const QidLen = 13
QidLen is the length of a Qid in bytes.
Variables ¶
var ErrMaxSize = errors.New("message exceeds msize")
ErrMaxSize is returned during the parsing process if a message exceeds the maximum size negotiated during the Tversion/Rversion transaction.
Functions ¶
Types ¶
type BadMessage ¶
type BadMessage struct { Err error // the reason the message is invalid // contains filtered or unexported fields }
BadMessage represents an invalid message.
func (BadMessage) Len ¶
func (m BadMessage) Len() int64
func (BadMessage) String ¶
func (m BadMessage) String() string
func (BadMessage) Tag ¶
func (m BadMessage) Tag() uint16
Tag returns the tag of the errant message. Servers should cite the same tag when replying with an Rerror message.
type Decoder ¶
type Decoder struct { // MaxSize is the maximum size message that a Decoder will accept. If // MaxSize is -1, a Decoder will accept any size message. MaxSize int64 // contains filtered or unexported fields }
A Decoder provides an interface for reading a stream of 9P messages from an io.Reader. Successive calls to the Next method of a Decoder will fetch and validate 9P messages from the input stream, until EOF is encountered, or another error is encountered.
A Decoder is not safe for concurrent use. Usage of any Decoder method should be delegated to a single thread of execution or protected by a mutex.
Example ¶
package main import ( "io" "io/ioutil" "log" "net" "aqwari.net/net/styx/styxproto" ) func main() { l, err := net.Listen("tcp", ":564") if err != nil { log.Fatal(err) } rwc, err := l.Accept() if err != nil { log.Fatal(err) } d := styxproto.NewDecoder(rwc) e := styxproto.NewEncoder(rwc) for d.Next() { switch msg := d.Msg().(type) { case styxproto.Tversion: log.Printf("Client wants version %s", msg.Version()) e.Rversion(8192, "9P2000") case styxproto.Tread: e.Rread(msg.Tag(), []byte("data data")) case styxproto.Twrite: log.Printf("Receiving %d bytes from client", msg.Count()) io.Copy(ioutil.Discard, msg) } } }
Output:
func NewDecoder ¶
NewDecoder returns a Decoder with an internal buffer of size DefaultBufSize.
func NewDecoderSize ¶
NewDecoderSize returns a Decoder with an internal buffer of size max(MinBufSize, bufsize) bytes. A Decoder with a larger buffer can provide more 9P messages at once, if they are available. This may improve performance on connections that are heavily multiplexed, where there messages from independent sessions that can be handled in any order.
func (*Decoder) Err ¶
Err returns the first error encountered during parsing. If the underyling io.Reader was closed in the middle of a message, Err will return io.ErrUnexpectedEOF. Otherwise, io.EOF is not considered to be an error, and is not relayed by Err.
Invalid messages are not considered errors, and are represented in the Messages slice as values of type BadMessage. Only problems with the underlying io.Reader are considered errors.
func (*Decoder) Msg ¶
Msg returns the last 9P message decoded in the stream. It returns a non-nil message if and only if the last call to the Decoder's Next method returned true. The return value of Msg is only valid until the next call to a decoder's Next method.
func (*Decoder) Next ¶
Next fetches the next 9P message from the Decoder's underlying io.Reader. If an error is encountered reading from the underlying stream, Next will return false, and the Decoder's Err method will return the first error encountered.
If Next returns true, the Msg method of the Decoder will return the decoded 9P message.
type Encoder ¶
type Encoder struct { MaxSize int64 // contains filtered or unexported fields }
An Encoder writes 9P messages to an underlying io.Writer.
func NewEncoder ¶
NewEncoder creates a new Encoder that writes 9P messages to w. Encoders are safe to use from multiple goroutines. An Encoder does not perform any buffering of messages.
func (*Encoder) Err ¶
Err returns the first error encountered by an Encoder when writing data to its underlying io.Writer.
func (*Encoder) Rerror ¶
Rerror writes a new Rerror message to the underlying io.Writer. Errfmt may be a printf-style format string, with values filled in from the argument list v. If the error string is longer than MaxErrorLen bytes, it is truncated.
func (*Encoder) Rread ¶
Rread writes a new Rread message to the underlying io.Writer. If len(data) is greater than the Encoder's Msize, it is broken up into multiple Rread messages. Rread returns the number of bytes written, plus any IO errors encountered.
func (*Encoder) Rstat ¶
Rstat writes an Rstat message to the underlying io.Writer. If the Stat is larger than the maximum size allowed by the NewStat function, a run-time panic occurs.
func (*Encoder) Rversion ¶
Rversion writes an Rversion message to the underlying io.Writer. If the version string is longer than MaxVerisonLen, it is truncated.
func (*Encoder) Rwalk ¶
Rwalk writes a new Rwalk message to the underlying io.Writer. An error is returned if wqid has more than MaxWElem elements.
func (*Encoder) Rwrite ¶
Rwrite writes an Rwrite message to the underlying io.Writer. If count is greater than the maximum value of a 32-bit unsigned integer, a run-time panic occurs.
func (*Encoder) Tattach ¶
Tattach writes a new Tattach message to the underlying io.Writer. If the client does not want to authenticate, afid should be NoFid. The uname and aname parameters will be truncated if they are longer than MaxUidLen and MaxAttachLen, respectively.
func (*Encoder) Tauth ¶
Tauth writes a Tauth message to enc's underlying io.Writer. The uname and aname parameters will be truncated if they are longer than MaxUidLen and MaxAttachLen, respectively.
func (*Encoder) Tcreate ¶
Tcreate writes a new Tcreate message to the underlying io.Writer. If name is longer than MaxFilenameLen, it is truncated.
func (*Encoder) Tread ¶
Tread writes a new Tread message to the underlying io.Writer. An error is returned if count is greater than the maximum value of a 32-bit unsigned integer.
func (*Encoder) Tversion ¶
Tversion writes a Tversion message to the underlying io.Writer. The Tag of the written message will be NoTag. If the version string is longer than MaxVersionLen, it is truncated.
func (*Encoder) Twalk ¶
Twalk writes a new Twalk message to the underlying io.Writer. An error is returned if wname is longer than MaxWElem elements, or if any single element in wname is longer than MaxFilenameLen bytes long.
type Msg ¶
type Msg interface { // Tag is a transaction identifier. No two pending T-messages may // use the same tag. All R-messages must reference the T-message // being answered by using the same tag. Tag() uint16 // Len returns the total length of the message in bytes. Len() int64 // contains filtered or unexported methods }
A Msg is a 9P message. 9P messages are sent by clients (T-messages) and servers (R-messages).
type Qid ¶
type Qid []byte
A Qid represents the server's unique identification for the file being accessed: two files on the same server hierarchy are the same if and only if their qids are the same.
func NewQid ¶
NewQid writes the 9P representation of a Qid to buf. If buf is not long enough to hold a Qid (13 bytes), io.ErrShortBuffer is returned. NewQid returns any remaining space in buf after the Qid has been written.
Example ¶
package main import ( "fmt" "log" "aqwari.net/net/styx/styxproto" ) func main() { buf := make([]byte, 13) qid, buf, err := styxproto.NewQid(buf, 1, 369, 0x84961) if err != nil { log.Fatal(err) } fmt.Println(qid) }
Output: type=1 ver=369 path=84961
func (Qid) Path ¶
Path is an integer unique among all files in the hierarchy. If a file is deleted and recreated with the same name in the same directory, the old and new path components of the qids should be different.
type Rattach ¶
type Rattach []byte
The Rattach message contains a server's reply to a Tattach request. As a result of the attach transaction, the client will have a connection to the root directory of the desired file tree, represented by the returned qid.
type Rauth ¶
type Rauth []byte
Servers that require authentication will reply to Tauth requests with an Rauth message. If a server does not require authentication, it can reply to a Tauth message with an Rerror message.
type Rerror ¶
type Rerror []byte
The Rerror message (there is no Terror) is used to return an error string describing the failure of a transaction.
type Rflush ¶
type Rflush []byte
A server should answer a Tflush message immediately with an Rflush message that echoes the tag (not oldtag) of the Tflush message. If it recognizes oldtag as the tag of a pending transaction, it should abort any pending response and discard that tag. A Tflush can never be responded to with an Rerror message.
type Ropen ¶
type Ropen []byte
An Ropen message contains a servers response to a Topen request. An Ropen message is only sent if the server determined that the requesting user had the proper permissions required for the Topen to succeed, otherwise Rerror is returned.
type Rread ¶
type Rread struct {
// contains filtered or unexported fields
}
The Rread message returns the bytes requested by a Tread message. The data portion of an Rread message can be consumed using the io.Reader interface.
type Rversion ¶
type Rversion []byte
An Rversion reply is sent in response to a Tversion request. It contains the version of the protocol that the server has chosen, and the maximum size of all successive messages.
func (Rversion) Msize ¶
Msize returns the maximum size (in bytes) of any 9P message that it will send or accept, and must be equal to or less than the maximum suggested in the preceding Tversion message. After the Rversion message is received, both sides of the connection must honor this limit.
func (Rversion) Version ¶
Version identifies the level of the protocol that the server supports. If a server does not understand the protocol version sent in a Tversion message, Version will return the string "unknown". A server may choose to specify a version that is less than or equal to that supported by the client.
type Rwalk ¶
type Rwalk []byte
An Rwalk message contains a server's reply to a successful Twalk request. If the first path in the corresponding Twalk request cannot be walked, an Rerror message is returned instead.
type Stat ¶
type Stat []byte
The Stat structure describes a directory entry. It is contained in Rstat and Twstat messages. Tread requests on directories return a Stat structure for each directory entry. A Stat implements the os.FileInfo interface.
func NewStat ¶
NewStat creates a new Stat structure. The name, uid, gid, and muid fields affect the size of the stat-structure and should be considered read-only once the Stat is created. An error is returned if name is more than MaxFilenameLen bytes long or uid, gid, or muid are more than MaxUidLen bytes long. Additional fields in the Stat structure can be set by using the appropriate Set method on the Stat value.
Example ¶
package main import ( "fmt" "log" "aqwari.net/net/styx/styxproto" ) func main() { buf := make([]byte, 100) s, buf, err := styxproto.NewStat(buf, "messages.log", "root", "wheel", "") if err != nil { log.Fatal(err) } s.SetLength(309) s.SetMode(0640) fmt.Println(s) }
Output: type=0 dev=0 qid="type=0 ver=0 path=0" mode=640 atime=0 mtime=0 length=309 name="messages.log" uid="root" gid="wheel" muid=""
func (Stat) Dev ¶
The 4-byte dev field contains implementation-specific data that is outside the scope of the 9P protocol. In Plan 9, it holds an identifier for the block device that stores the file.
func (Stat) Mode ¶
Mode contains the permissions and flags set for the file. Permissions follow the unix model; the 3 least-significant 3-bit triads describe read, write, and execute access for owners, group members, and other users, respectively.
type Tattach ¶
type Tattach []byte
The attach message serves as a fresh introduction from a user on the client machine to the server.
func (Tattach) Afid ¶
On servers that require authentication, afid serves to authenticate a user, and must have been established in a previous Tauth request. If a client does not wish to authenticate, afid should be set to NoFid.
type Tauth ¶
type Tauth []byte
The Tauth message is used to authenticate users on a connection.
func (Tauth) Afid ¶
The afid of a Tversion message establishes an 'authentication file'; after a Tauth message is accepted by the server, a client must carry out the authentication protocol by performing I/O operations on afid. Any protocol may be used and authentication is outside the scope of the 9P protocol.
type Tclunk ¶
type Tclunk []byte
The clunk request informs the file server that the current file represented by fid is no longer needed by the client. The actual file is not removed on the server unless the fid had been opened with ORCLOSE.
type Tflush ¶
type Tflush []byte
When the response to a request is no longer needed, such as when a user interrupts a process doing a read(2), a Tflush request is sent to the server to purge the pending response.
type Topen ¶
type Topen []byte
The open request asks the file server to check permissions and prepare a fid for I/O with subsequent read and write messages.
func (Topen) Fid ¶
Fid is the fid of the file to open, as established by a previous transaction (such as a succesful Twalk).
func (Topen) Mode ¶
The mode field determines the type of I/O, and is checked against the permissions for the file:
0 (OREAD) read access 1 (OWRITE) write access 2 (ORDWR) read and write access 3 (OEXEC) execute access
If mode has the OTRUNC (0x10) bit set, the file is to be truncated, which requires write permission (if the file is append-only, and permission is granted, the open succeeds but the file will not be truncated)
If the mode has the ORCLOSE (0x40) bit set, the file is to be removed when the fid is clunked, which requires permission to remove the file from its directory. All other bits in mode should be zero.
It is illegal to write a directory, truncate it, or attempt to remove it on close.
type Tread ¶
type Tread []byte
func (Tread) Count ¶
Count is the number of bytes to read from the file. Count cannot be more than the maximum value of a 32-bit unsigned integer.
type Tversion ¶
type Tversion []byte
The version request negotiates the protocol version and message size to be used on the connection and initializes the connection for I/O. Tversion must be the first message sent on the 9P connection, and the client cannot issue any further requests until it has received the Rversion reply.
type Twalk ¶
type Twalk []byte
A Twalk message is used to descend a directory hierarchy.
func (Twalk) Fid ¶
The Twalk message contains the fid of the directory it intends to descend into. The Fid must have been established by a previous transaction, such as an attach.
func (Twalk) Newfid ¶
Newfid contains the proposed fid that the client wishes to associate with the result of traversing the directory hierarchy.
type Twrite ¶
type Twrite struct {
// contains filtered or unexported fields
}
The Twrite message is sent by a client to write data to a file. The data portion of a Twrite request can be accessed via the io.Reader interface.