Module Styx.Proto

Encoding and decoding of 9P2000 message streams.

val min_msg_size : int

min_msg_size is the size of the smallest valid message in bytes, including its 4-byte size header.

val max_welem : int

max_welem is the maximum number of files visited in a single Twalk request.

val max_filename : int

max_filename is the maximum length of a file name. The 9P protocol does not specify this; the value used by this module is chosen to be similar to most common file systems.

val max_username : int

max_username is the maximum length of a user name. It is imposed not by the protocol, but by this library.

val min_msize : int

min_msize is the smallest message size that can accomodate any message.

val max_io_hdr : int

max_io_hdr is the header size of a Twrite message. The maximum value for iounit for a connection with an msize of n is n - max_io_hdr.

module Fid : sig ... end

A Fid is a client-side identifier for a file. Clients may have any number of fids open for the same file. Some fids may be prepared for Tread and Twrite requests by a Topen or Tcreate request.

module Tag : sig ... end

A Tag is a 2-byte identifier for a client request. No two in-flight requests may have the same tag. The special tag notag is reserved for Tversion requests.

module Tversion : sig ... end

A Tversion request indicates the latest 9P version and largest message size that a client is willing to use.

module Rversion : sig ... end

An Rversion response indicates the 9P version and max message size the server will use. The client must abide by these values.

module Tauth : sig ... end

A Tauth request establishes a channel to authenticate a user.

module Rauth : sig ... end

An Rauth request completes setup of the auth file. Completion of the auth request does not imply that the user is authenticated; The user must complete authentication by tunneling an agreed-upon authentication file through the authentication file. The specific authentication protocol is outside the scope of 9P.

module Rerror : sig ... end

An Rerror signifies a non-fatal error encountered while the server was handling a client's request, such as a missing file or insufficient permissions.

module Tattach : sig ... end

The Tattach message establishes a 9P session for a single user and file system root.

module Rattach : sig ... end

Rattach completes the creation of the 9P session for the user. The returned qid describes the root of the file system, which should be a directory.

module Tflush : sig ... end

Tflush requests cancellation of a previous request. A server should cancel work on the request and respond with an Rflush message.The server should respond to a Tflush immediately and may only respond with an Rflush message. If oldtag represents an existing request, it should abort any pending work for that request and discard the tag.

module Rflush : sig ... end

Rflush acknowledges a request cancellation. If the response to the cancelled request was already sent and received by the client, the client must ignore the Rflush message and proceed as if the request succeeded. A server should not send the response to the original request after the Rflush.

module Twalk : sig ... end

Twalk traverses the directory hierarchy from an existing file to another file up to max_welem path elements away.

module Rwalk : sig ... end

An Rwalk message responds with the Qid for each traversed element. If no elements were successfully traversed, a server should reply with an Rerror message. Otherwise, the Rwalk message should contain a Qid entry for each path element that was successfully traversed.

module Topen : sig ... end

Topen prepares a fid for I/O with the provided options.

module Ropen : sig ... end

Ropen completes a Topen request. After Ropen is received, the fid used in the Topen can be used in Twrite or Tread calls, according to the flags passed in the Topen request. The returned iounit is the maximum number of bytes of data that a server will handle for the file in a single request.

module Tcreate : sig ... end

Tcreate requests a new file to be created with the given name and permissions. It requires write access to the parent directory.

module Rcreate : sig ... end

Rcreate confirms successful creation of a file. After an Rcreate, the fid is opened and ready for I/O. This can be leveraged to create and open an exclusive use file in a single, atomic operation to avoid races with other 9P clients.

module Tread : sig ... end

A Tread requests data from a specific range in an open file.

module Rread : sig ... end

An Rread returns the requested data from a file. It is not an error for the data returned to be less than the data requested.

module Twrite : sig ... end

A Twrite request provides data to be recorded in an open file at a given offset.

module Rwrite : sig ... end

Rwrite returns the number of bytes recorded in the file.

module Tclunk : sig ... end

Tclunk closes a fid for I/O and disassociates it from any file. Regardless of the success or failure of a Tclunk request, once it is sent, the fid is no longer considered to be associated with the file, and can be re-used in another Twalk or Tattach request.

module Rclunk : sig ... end

Rclunk acknowledges a file closure. Most clients will expect a successful Rclunk to indicate that any cached or buffered data has been flushed to persistent storage, analagous to the close(2) system call. If the file was created with the ORCLOSE flag, it is removed.

module Tremove : sig ... end

Tremove deletes the file associated with a fid. It requires write access to the file's parent directory. Even if the remove fails, the associated fid is clunked and no longer associated with the file.

module Rremove : sig ... end

Rremove acknowledges that the requested file was successfully removed.

module Tstat : sig ... end

Tstat requests file attributes for a file. A stat request requires no special permission; if a client is able to walk to a file, they are able to send a Tstat request for it.

module Rstat : sig ... end

Rstat carries a Stat structure for the requested file.

module Twstat : sig ... end

Twstat allows for changes to be made to file attributes. A file may be renamed in this way but its location cannot be changed.

module Rwstat : sig ... end

Rwstat acknowledges the updated file attributes. It can be expected that the version field of a file's Qid is incremented after this, if a change was made.

type _ message =
| Invalid : string message

The message is not well-formed

| Partial : int message

The message is incomplete

| Tversion : Tversion.t message
| Rversion : Rversion.t message
| Tauth : Tauth.t message
| Rauth : Rauth.t message
| Rerror : Rerror.t message
| Tflush : Tflush.t message
| Rflush : Rflush.t message
| Tattach : Tattach.t message
| Rattach : Rattach.t message
| Twalk : Twalk.t message
| Rwalk : Rwalk.t message
| Topen : Topen.t message
| Ropen : Ropen.t message
| Tcreate : Tcreate.t message
| Rcreate : Rcreate.t message
| Tread : Tread.t message
| Rread : Rread.t message
| Twrite : Twrite.t message
| Rwrite : Rwrite.t message
| Tclunk : Tclunk.t message
| Rclunk : Rclunk.t message
| Tremove : Tremove.t message
| Rremove : Rremove.t message
| Tstat : Tstat.t message
| Rstat : Rstat.t message
| Twstat : Twstat.t message
| Rwstat : Rwstat.t message

The message GADT indicates the type of the message argument passed to a handler in the parse function.

type 'a handler = {
handle_msg : t. int -> Tag.t -> 't message -> 't -> 'a;
}

parse passes validated messages as a GADT to avoid allocations of boxed variants. The function f can be declared thus:

let handle_msg (type t) size tag (msg_type:t Proto.message) msg =
  match msg_type with
  | Tversion -> handle_tversion msg
  | Rversion -> handle_rversion msg
  ... 

while recursive functions must use the more explicit syntax:

let handle_msg : type t. size:_ -> tag:_ -> t Proto.message -> t -> _ =
 fun ~size ~tag msg_type msg ->
  match msg_type with
  | Tversion -> handle_tversion msg
  | Rversion -> handle_rversion msg
  ... 
val parse : 'a handler -> Iovec.t -> 'a

parse f iov parses the first message in iov and passes it to f. If the next message is not well-formed, the message type is Invalid. If iov only covers a partial message, but is otherwise well-formed, the message type is Partial, and its value is minimum number of additional bytes needed to read the full message.

Messages are validated structurally but not semantically. For example, the Fid.nofid and Tag.notag identifiers are not legal for most requests, but this function will happily decode messages that use them incorrectly. The only robust response to an Invalid connection is to close the connection.