On this page:
6.1 Protocol Messages
6.1.1 Messages
message
message: t
message: r
message: t: version
message: r: version
message: t: auth
message: r: auth
message: t: attach
message: r: attach
message: r: error
message: t: flush
message: r: flush
message: t: walk
message: r: walk
message: t: open
message: r: open
message: t: openfd
message: r: openfd
message: t: create
message: r: create
message: t: read
message: r: read
message: t: write
message: r: write
message: t: clunk
message: r: clunk
message: t: remove
message: r: remove
message: t: stat
message: r: stat
message: t: wstat
message: r: wstat
6.1.2 Input and Output
max-message-size
read-message
write-message
6.1.3 Packings
current-tags
tag/ p
current-fids
fid/ p
6.2 Event Loops
start-client
start-server

6 Low-level Network Layer

 (require (planet "network.ss" ("murphy" "9p.plt" 1 0)))
This module re-exports all bindings from the "network/message.ss" and "network/event-loop.ss" modules.

6.1 Protocol Messages

 (require (planet "message.ss" ("murphy" "9p.plt" 1 0) "network"))
Structures and utilities to represent messages exchanged between 9P clients and servers.
See intro(9P) for the original protocol message definition overview.

6.1.1 Messages

(struct message (tag)
  #:transparent)
  tag : (box/c (or/c natural-number/c #f))
The base type of all 9P protocol messages.

(struct (message:t message) ()
  #:transparent)
The base type of all 9P protocol messages initiating a request. These messages are normally only transmitted from the client to the server.

(struct (message:r message) ()
  #:transparent)
The base type of all 9P protocol messages responding to a request. These messages are normally only transmitted from the server to the client.

(struct (message:t:version message:t) (max-size version)
  #:transparent)
  max-size : natural-number/c
  version : string?
Protocol negotiation request. See version(9P) for more information.

(struct (message:r:version message:r) (max-size version)
  #:transparent)
  max-size : natural-number/c
  version : string?
Protocol negotiation response. See version(9P) for more information.

(struct (message:t:auth message:t) (afid user root)
  #:transparent)
  afid : (box/c (or/c natural-number/c #f))
  user : string?
  root : string?
Request to open an authentication channel. See auth(9P) for more information.

(struct (message:r:auth message:r) (aqid)
  #:transparent)
  aqid : qid?
Authentication channel open response. See auth(9P) for more information.

(struct (message:t:attach message:t) (fid afid user root)
  #:transparent)
  fid : (box/c (or/c natural-number/c #f))
  afid : natural-number/c
  user : string?
  root : string?
Filesystem root attach request. See attach(9P) for more information.

(struct (message:r:attach message:r) (qid)
  #:transparent)
  qid : qid?
Attached filesystem root response. See attach(9P) for more information.

(struct (message:r:error message:r) (name)
  #:transparent)
  name : string?
Generic error response. See error(9P) for more information.

The only message that has no corresponding request message but may be sent in response to most other requests.

(struct (message:t:flush message:t) (old-tag)
  #:transparent)
  old-tag : natural-number/c
Previous message flush request. See flush(9P) for more information.

The higher-level code in this 9P implementation handles this message automatically.

(struct (message:r:flush message:r) ()
  #:transparent)
Flushed previous message response. See flush(9P) for more information.

The higher-level code in this 9P implementation handles this message automatically.

(struct (message:t:walk message:t) (from-fid to-fid names)
  #:transparent)
  from-fid : natural-number/c
  to-fid : (box/c (or/c natural-number/c #f))
  names : (vectorof string?)
File walk request. See walk(9P) for more information.

(struct (message:r:walk message:r) (qids)
  #:transparent)
  qids : (vectorof qid?)
Walked file response. See walk(9P) for more information.

(struct (message:t:open message:t) (fid mode)
  #:transparent)
  fid : natural-number/c
  mode : natural-number/c
File open request. See open(9P) for more information.

(struct (message:r:open message:r) (qid i/o-unit)
  #:transparent)
  qid : qid?
  i/o-unit : natural-number/c
Opened file response. See open(9P) for more information.

(struct (message:t:openfd message:t) (fid mode)
  #:transparent)
  fid : natural-number/c
  mode : natural-number/c
File open as descriptor request. See openfd(9P) for more information.

The higher-level code in this 9P implementation doesn’t support this message since it is impossible to implement when TCP sockets are used as the transport layer.

(struct (message:r:openfd message:r) (qid i/o-unit fd)
  #:transparent)
  qid : qid?
  i/o-unit : natural-number/c
  fd : natural-number/c
Opened file open as descriptor response. See openfd(9P) for more information.

The higher-level code in this 9P implementation doesn’t support this message since it is impossible to implement when TCP sockets are used as the transport layer.

(struct (message:t:create message:t) (fid name permissions mode)
  #:transparent)
  fid : natural-number/c
  name : string?
  permissions : natural-number/c
  mode : natural-number/c
File creation request. See create(9P) for more information.

(struct (message:r:create message:r) (qid i/o-unit)
  #:transparent)
  qid : qid?
  i/o-unit : natural-number/c
Created file response. See create(9P) for more information.

(struct (message:t:read message:t) (fid offset size)
  #:transparent)
  fid : natural-number/c
  offset : natural-number/c
  size : natural-number/c
Data read request. See read(9P) for more information.

(struct (message:r:read message:r) (data)
  #:transparent)
  data : natural-number/c
Read data response. See read(9P) for more information.

(struct (message:t:write message:t) (fid offset data)
  #:transparent)
  fid : natural-number/c
  offset : natural-number/c
  data : bytes?
Data write request. See write(9P) for more information.

(struct (message:r:write message:r) (size)
  #:transparent)
  size : natural-number/c
Written data response. See write(9P) for more information.

(struct (message:t:clunk message:t) (fid)
  #:transparent)
  fid : natural-number/c
File handle clunk request. See clunk(9P) for more information.

(struct (message:r:clunk message:r) ()
  #:transparent)
Clunked file handle response. See clunk(9P) for more information.

(struct (message:t:remove message:t) (fid)
  #:transparent)
  fid : natural-number/c
File and handle remove request. See remove(9P) for more information.

(struct (message:r:remove message:r) ()
  #:transparent)
Removed file and handle response. See remove(9P) for more information.

(struct (message:t:stat message:t) (fid)
  #:transparent)
  fid : natural-number/c
Directory entry information request. See stat(9P) for more information.

(struct (message:r:stat message:r) (stat)
  #:transparent)
  stat : stat?
Directory entry information response. See stat(9P) for more information.

(struct (message:t:wstat message:t) (fid stat)
  #:transparent)
  fid : natural-number/c
  stat : stat?
Directory entry information change request. See wstat(9P) for more information.

(struct (message:r:wstat message:r) ()
  #:transparent)
Changed directory entry information response. See wstat(9P) for more information.

6.1.2 Input and Output

(max-message-size)  natural-number/c
(max-message-size size)  void?
  size : natural-number/c
The maximum bytes size allowable for a protocol message. read-message and write-message throw errors if the messages they handle exceed this size.

The parameter is also used during protocol negotiation between client and server. Inside the server, on threads handling client requests, the parameter is set to the value negotiated with the client.

(read-message [in])  message?
  in : input-port? = (current-input-port)
Reads a 9P message in binary format from the input port in.

(write-message message [out])  void?
  message : message?
  out : output-port? = (current-output-port)
Writes the given 9P message to the output port out in binary format.

6.1.3 Packings

(current-tags)  (and/c hash? (not/c immutable?))
(current-tags table)  void?
  table : (and/c hash? (not/c immutable?))
A table tracking message tag numbers that are in use in the current thread.

tag/p : packing?
A 16 bit unsigned integer packing. Values produced and consumed by the packing are contained within boxes. When a box containg #f is packed, a random number that is not yet present as a key in (current-tags) is selected, registered in the table with the associated value #t and placed in the box.

If a tag needs to be generated but there are too many tags registered in the table, tag/p raises a 9P filesystem exception with the message EAGAIN.

(current-fids)  (and/c hash? (not/c immutable?))
(current-fids table)  void?
  table : (and/c hash? (not/c immutable?))
A table tracking file identifiers that are in use in the current thread.

fid/p : packing?
A 32 bit unsigned integer packing. Values produced and consumed by the packing are contained within boxes. When a box containg #f is packed, a random number that is not yet present as a key in (current-fids) is selected, registered in the table with the associated value #t and placed in the box.

If a tag needs to be generated but there are too many tags registered in the table, tag/p raises a 9P filesystem exception with the message EMFILE.

6.2 Event Loops

 (require (planet "event-loop.ss" ("murphy" "9p.plt" 1 0) "network"))
Basic event loops to implement 9P network clients and servers over TCP sockets.

(start-client hostname    
  [port-no    
  local-hostname    
  local-port-no])  
(-> message:t? message:r?)
(-> any/c any)
custodian?
  hostname : string?
  port-no : (integer-in 1 65535) = 564
  local-hostname : (or/c string? #f) = #f
  local-port-no : (or/c (integer-in 1 65535) #f) = #f
Starts a client event loop in a new thread managed by a new custodian after establishing a TCP connection to the server specified by the hostname and port-no and negotiating the 9P protocol version.

Returns three values:
  • A request submitting procedure. You pass a message of type message:t to the procedure, it creates a fresh reply channel, communicates the message and the channel to the event loop thread, waits for a reply on the channel and returns the reply message of type message:r.

    Replies of type message:r:error are automatically converted into exceptions of type exn:fail:filesystem:9p.

    Messages of type message:t:flush and message:r:flush are handled automatically by converting from and to exceptions of type exn:break.

  • A file identifier clearing procedure. File identifiers can be auto-generated when serializing request messages for network transport but they cannot be dropped from the table of current identifiers fully automatically: In case you have allocated a file identifier automatically but you do not clunk or remove it, for example because the request message for which the identifier was created returned an error response, you should call this procedure with the file identifier as an argument to release the identifier for future reuse.

  • The custodian managing the event loop thread and the network connection. Simply shutdown the custodian to terminate the client event loop.

(start-server t-handler    
  fid-cleanup    
  [port-no    
  max-allow-wait    
  reuse?    
  hostname])  custodian?
  t-handler : (-> message:t? message:r?)
  fid-cleanup : (-> any/c any)
  port-no : (integer-in 0 65535) = 564
  max-allow-wait : natural-number/c = 4
  reuse? : any/c = #f
  hostname : (or/c string? #f) = #f
Starts a server event loop in a new thread managed by a new custodian after starting to listen on a TCP socket for the specified hostname and port-no. Another thread with a message processing loop is spawned for every incoming connection.

Each of the message processors calls t-handler on incoming messages of type message:t, again in a new thread for every incoming request. Thus multiple requests from the same client can run in parallel. When t-handler returns a response of type message:r, that message is communicated back to the message processor which sends it to the client. When t-handler raises an exception of type exn:fail:filesystem:9p, it is caught and converted into a in a response of type message:r:error.

t-handler should respond sensibly to breaks since client requests to flush a message that has not been responded to will result in a break being sent to the message’s handling thread.

t-handler is called in a dynamic environment with the following differences to the one in which start-server was called: current-custodian is parameterized to the custodian managing the whole server event loop, max-message-size is parameterized to the negotiated maximum message size of the current 9P connection, current-tags is parameterized to #f, current-fids is parameterized to a hash table that can be used to track file identifiers. This hash table is the same for all request handlers spawned for the same client connection. Initially it contains a single entry mapping the file identifier 4294967295 to the value #f. When the message processor for a client connection terminates, it calls fid-cleanup on any values stored in the hash table that are not #f.

start-server returns the custodian managing the event loop threads and the network connections. Simply shutdown the custodian to terminate the server event loop.