Categorygithub.com/frobnitzem/go-p9p
modulepackage
1.1.0
Repository: https://github.com/frobnitzem/go-p9p.git
Documentation: pkg.go.dev

# README

p9p

GoDoc Apache licensed Go Report Card CI Test

A modern, performant 9P library for Go.

For API documentation, see the GoDoc.

Refer to 9P's documentation for more details on the protocol.

Example

Download the package in the usual way:

go get github.com/frobnitzem/go-p9p

Now run the server and client. Since there's no authentication, it's safest to put it into a unix socket.

cd $HOME/go/frobnitzem/go-p9p
go run cmd/9ps/main.go -root $HOME/src -addr unix:/tmp/sock9 &
chmod 700 /tmp/sock9
go run cmd/9pr/main.go -addr unix:/tmp/sock9

You should get a prompt,

/ 🐳 >

There's actually a tab-autocomplete to show you commands to run.

Bring the server down with:

kill %
rm /tmp/sock9

Build your own filesystem

To build a filesystem using this library, implement the FileSys interface, and then pass it to SFileSys. For details on the FileSys interface, see filesys.go. For examples, see ufs/ and sleepfs/ subdirectories.

For a main program running the ufs server, see cmd/9fs/.

In case you don't already have a 9p client, try cmd/9fr/, but note it is not full-featured.

Alternatively, if you want to implement a server that works at a lower level of the stack, you can implement a Session interface directly. See session.go for the interface definition and servefs.go for an implementation at this level.

Protocol Stack

This package handles the 9P protocol by implementing a stack of layers. For the server, each layer does some incremental translation of the messages "on the wire" into program state. The client is opposite, translating function calls into wire representations, and invoking client callbacks with responses from the server.

Applications can pick one of the layers to interact with. Lower layers generally require more work on the applications side (tracking state, encoding messages, etc.). It's generally recommended to interface only with the uppermost layer's API.

Extending the layers upward to make even simpler interface API-s, as well as implementing proper authentication and session encryption is on the TODO list.

Server Stack

sfilesys.go: SFileSys(fs FileSys) Session

  • Creates a Session type from an FileSys
  • The FileSys represents a fileserver broken into 3 levels, AuthFile-s, Dirent-s, and Files
  • Rather than track Fid-s, calls to Dirent-s create more Dirent and Files.

ssesssion.go: Dispatch(session Session) Handler

  • Delegates each type of messages.go:Message to a function call (from Session).
  • Tags and TFlush-s are handled at this level, so higher levels do not see them. Instead, they see context.Context objects to indicate potential cancellation.

serveconn.go: ServeConn(ctx context.Context, cn net.Conn, handler Handler) error

  • Negotiates protocol (with a timeout of 1 second).
  • Calls server loop, reading messages and sending them to the handler.
  • Version messages are handled at this level. They have the effect of deleting the current session and starting a new one. (Note: Check this to be sure.)

serverconn.go: (c *conn) serve() error

  • Server loop, strips Tags and TFlush messages
  • details:
    • runs reader and writer goroutines
    • maps from Tags to activeRequest structures
    • spawns a goroutine to call c.handler.Handle on every non-TFlush
      • these handlers get new contexts
    • for TFlush, cancels the corresponding call

Client Stack

cfilesys.go: CFileSys(session Session) FileSys

  • Creates an FileSys from a Session type
  • The FileSys wraps up the session API so the user does not need to see Fid-s or Qid-s, unless you want to.

// Note: we could make into CSession(Handler) (Session, error) client.go: CSession(ctx context.Context, conn net.Conn) (Session, error)

  • negotiates protocol, returns client object
  • client object has Walk/Stat/Open/Read methods that appear like synchronous send/receive pairs. Many requests can be sent in parallel, however (e.g. one goroutine each), and the transport will handle them in parallel, doing tag matching to return to the correct call.

transport.go: func newTransport(ctx context.Context, ch Channel) roundTripper

  • starts a handle goroutine to take messages off the wire and invoke waiting response actions in the client.
  • roundTripper uses an internal channel to communicate with the handle so that each roundTripper can be synchronous, while the handler actually handles may requests.

Common lower-layers

channel.go: NewChannel(conn net.Conn, msize int) Channel

  • typical argument for codec is codec9p
  • called by ServeConn to serialize read/write from the net.Conn
  • Channel interface provides ReadFcall, WriteFcall, MSize, SetMSize

channel.go: (ch *channel) WriteFcall(ctx context.Context, fcall *Fcall) error channel.go: channel.go: (ch *channel) ReadFcall(ctx context.Context, fcall *Fcall) error

  • check context for I/O cancellations
  • last check on Msize (may result in error)
  • for writing, call codec.Marshal, then sendmsg()
  • for reading, call readmsg, then codec.Unmarshal

messages.go: newMessage(typ FcallType) (Message, error)

  • called by encoding.go to write out structs (e.g. MessageTopen) for each type of message

encoding.go: interface Codec

  • provides Marshal, Unmarshal, and Size for converting between []byte and 9P message structs.

Differences between client and server:

  • The server auto-generates calls to File.Close(). This function does nothing on the client side (use Clunk instead).

  • The client qids = Walk(names...) returns an Error/Warning when Walk returns a partial, incomplete walk to the destination. This happens if len(names) > 1 and walk returns len(qids) != len(names).

Server Locking Sequences

Lookup a Fid:

  1. assert Fid != NOFID
  2. lock session, lookup fid, unlock session
  3. lock ref
    • This ensures that the ref was unlocked at some past point.
  4. if ref.ent == nil, fid is being deleted, unlock and return "no fid"
  5. return ref in locked state
    • Client unlocks when they are done with operation on Fid.
    • This forces no parallel operations on Fid at all.
    • Convention: clone fids if you want parallel access.

Clunk/Remove a Fid:

  1. lock session, lookup fid, unlock session
  2. lock ref, lock session, delete fid:ref, unlock session, unlock ref
  3. close if ref.file != nil
  4. clunk/remove ref.ent
    • This doesn't work because we may get multiple Walk/Open/Stat requests in parallel with Clunk. We need a way to stop those actions, then clunk.

Auth:

  1. lock session, lookup afid (ensure not present), create locked aref, store afid:aref, unlock session
  2. call Auth function to set aref.afile
  3. unlock afid

Attach:

  1. if fs.RequireAuth()): a. lock session, lookup aref, unlock session b. lock aref, call ok := aref.afile.Success(), unlock aref c. assert ok
  2. ref := holdRef [lock session, lookup fid (ensure not present), create locked ref, store afid:aref, unlock session]
  3. ent, err := Root()
  4. if err { lock session, delete fid:ref, unlock session, return }
  5. set ref.ent = ent, unlock ref

Note: Rather than using a locked fid lookup table, we could have the dispatcher do fid lookups, and send requests on a channel dedicated to (a goroutine) serving only that fid. This may be an optimization, or it may not - only lots of work and profiling will tell. So, this has not been tried.

Copyright and license

Copyright © 2015 Docker, Inc. Copyright © 2023 UT-Battelle LLC. go-p9p is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

No description provided by the author
Find the result of Create(name) from the directory dir.
CSession returns a session using the connection.
DecodeDir decodes a directory entry from rd using the provided codec.
EncodeDir writes the directory to wr.
TODO(frobnitzem): validate required server returns to ensure non-nil.
GetVersion returns the protocol version from the context.
Helper function to check Dirent.Qid().Type for QTDIR bit.
NewChannel returns a new channel to read and write Fcalls with the provided connection and message size.
NewCodec returns a new, standard 9P2000 codec, ready for use.
NewFixedReaddir returns a Readdir that will return a fixed set of directory entries.
Wrap a Session, producing log messages to os.Stdout whenever Auth, Attach, Remove, and Stop are called.
NewReaddir returns a new Readdir to assist implementing server-side Readdir.
No description provided by the author
Normalize a path by removing all "" and "." elements, and treating all ".." as backspaces.
Overflow will return a positive number, indicating there was an overflow for the error.
ReaddirAll reads all the directory entries for the resource fid.
ServeConn the 9p handler over the provided network connection.
Create a session object able to respond to 9P calls.
SSession returns a handler that transforms messages into function calls (dispatching to Session's methods).
Determine the starting Dirent and path elements to send to Walk() in order to reach path p.
Returns -1 if any path elements are '.' or contain characters '/' or '\' or if .
Find the absolute path of names relative to dir.

# Constants

DefaultMSize messages size used to establish a session.
DefaultVersion for this package.
mode bit for append only files.
mode bit for authentication file.
Mode constants for use Dir.Mode.
mode bit for directories.
mode bit for exclusive use files.
mode bit for execute permission.
mode bit for mounted channel.
Mode constants for use Dir.Mode.
mode bit for read permission.
Mode constants for use Dir.Mode.
Mode constants for use Dir.Mode.
Mode constants for use Dir.Mode.
Mode constants for use Dir.Mode.
mode bit for non-backed-up files.
mode bit for write permission.
NOFID indicates the lack of an Fid.
NOTAG is a reserved values for messages sent before establishing a session, such as Tversion.
or'ed in, close on exec.
execute, == read but check execute permission.
or'ed in, remove on close.
read and write.
open for read.
Constants to use when opening files.
or'ed in (except for exec), truncate file first.
write.
type bit for append only files.
type bit for authentication file.
type bit for directories.
type bit for exclusive use files.
plain file.
type bit for mounted channel.
type bit for not-backed-up file.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.
Definitions for Fcall's used in 9P2000.

# Variables

9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
returned when timing out on the fcall.
returned when an unexpected message is encountered.
9p wire errors returned by Session interface methods.
returned when encountering unknown message type.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.
9p wire errors returned by Session interface methods.

# Structs

Simple context representing a past-due deadline.
Dir defines the structure used for expressing resources in stat/wstat and when reading directories.
Fcall defines the fields for sending a 9p formatted message.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
MessageRerror provides both a Go error type and message type.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
MessageVersion encodes the message body for Tversion and Rversion RPC calls.
No description provided by the author
No description provided by the author
No description provided by the author
Qid indicates the type, path and version of the resource returned by a server.
Readdir helps one to implement the server-side of Session.Read on directories.
FileSystem implementions gather more data than the required minimal information to send messages.
No description provided by the author

# Interfaces

No description provided by the author
Channel defines the operations necessary to implement a 9p message channel interface.
Codec defines the interface for encoding and decoding of 9p types.
Simplified interface for servers to implement files.
Simplified interface to a file that has been Open-ed.
Note: Like information from all ent/file inputs, the server should copy details from the AuthFile if you want to retain them internally past the lifetime of this function call.
Handler defines an interface for 9p message handlers.
Message represents the target of an fcall.
Session provides the first level of abstraction for a 9p connection.

# Type aliases

FcallType encodes the message type for the target Fcall.
Fid defines a type to hold Fid values.
Flag defines the flag type for use with open and create.
QType indicates the type of a resource within the Qid.
No description provided by the author
No description provided by the author
Tag uniquely identifies an outstanding fcall in a 9p session.