Changeset 27507 in project


Ignore:
Timestamp:
09/29/12 20:29:57 (7 years ago)
Author:
Alaric Snell-Pym
Message:

9p: Documented 9p-server

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wiki/eggref/4/9p

    r26747 r27507  
    311311
    312312This creates a new {{message}} object (see below) with a tag and the given {{type}}.  {{args}} are the message-contents.  It then sends this request to the server and awaits a response.  The response should match the request (a {{Twhatever}} should result in a {{Rwhatever}} message), or a condition of type {{(exn 9p-response-error)}} is signaled.  If the server returns an error (via {{Rerror}}), a condition of type {{(exn 9p-server-error)}} is signaled.  The response object (a message object) is returned.
     313
     314=== 9p-server
     315
     316This library lets you create your own 9p servers, allowing filesystems
     317implemented in Chicken Scheme to be mounted as part of a computer's
     318filesystem tree, or to be accessed by other 9p clients.
     319
     320Here we document the Scheme interfaces, but you need to read the 9P
     321protocol documentation to understand the semantics of the
     322operations.
     323
     324==== Usage
     325
     326  (use 9p-server)
     327  (use utf8)
     328
     329Again, utf8 is highly recommended but not strictly required.
     330
     331==== Serving interface
     332
     333<procedure>(server inport outport handlers)</procedure>
     334
     335The {{9p-server}} module exports a single procedure, {{{serve}}},
     336which provides the 9p server protocol on a provided pair of ports (one
     337for input, one for output). The caller must provide an alist mapping
     338symbolic names of 9p protocol operations to closures that implement
     339those operations. Some operations are optional, and default
     340implementations will be used if they are not provided, but some are
     341essential and must be provided or an error will be raised.
     342
     343The 9p protocol is somewhat asynchronous; multiple requests may be
     344submitted without the client waiting for responses, and the server may
     345respond to open requests in any order. In order to support this, the
     346handler procedures do not issue replies by returning a value, but by
     347calling one of a number of closures they are passed as arguments. Most
     348have a {{reply!}} argument to send a normal reply and an {{error!}}
     349argument to send an error response, but there may be others, which
     350will be discussed below.
     351
     352Most handlers that originate from a 9p protocol message are passed the
     353contents of the 9p request, which is a list, the format of which
     354depends on the request.
     355
     356The main exceptions are the initial {{version}} request that is part of
     357the connection setup process, which does block until the handler
     358directly returns the required value, and the {{disconnect}} request
     359that is called when a connection is closed and has no reply. When the
     360connection is closed, as soon as the {{disconnect}} handler returns,
     361{{serve}} returns to its caller.
     362
     363==== Connection management
     364
     365Typically, one would write a handler that binds a TCP socket and
     366spawns a thread for each connection accepted, which then invokes the
     367{{{serve}}} procedure with suitable arguments, like so:
     368
     369   (parameterize ((tcp-read-timeout #f)
     370                  (tcp-buffer-size 65536))
     371    (let ((listener (tcp-listen 1564)))
     372      (let accept-loop ()
     373        (receive (in out) (tcp-accept listener)
     374                 (thread-start! (make-thread
     375                                 (lambda ()
     376                                   (serve in out handlers)
     377                                   (close-input-port in)
     378                                   (close-output-port out)))))
     379        (accept-loop))))
     380
     381It is advisable to turn off the TCP read timeout, or the 9p server,
     382sitting blocked on a TCP read for the next request from the client,
     383will time out!
     384
     385The above code binds to TCP port 1564 rather than the traditional 9p
     386port of 564, in order to avoid needing to run as root. It can be
     387mounted on a Linux system with a command such as:
     388
     389   mount -t 9p localhost -o port=1564 /mnt
     390
     391It also assumes that the symbol {{{handlers}}} is bound to a suitable
     392alist of handlers in the current lexical environment. We shall now
     393examine the closures that should be found in that alist...
     394
     395==== FIDs
     396
     397The 9P protocol uses client-assigned handles called "fids" to refer to
     398server-side resources such as open files, open directories, or
     399authentication protocols. Operations that create a server-side object
     400provide a fid that the client would like to use to refer to that
     401object in future.
     402
     403The 9p-server module attempts to help with fid management by handling
     404a mapping between fid values and Scheme objects representing the state
     405of that server-side resource. Handlers that create an object are
     406passed a {{bind-fid!}} callback which, if invoked with an arbitrary
     407Scheme object, will bind that object to the fid. Handlers that operate
     408on a server-side object are passed the value bound to that fid as an
     409argument. Generally, you will use some mutable record type as the
     410state of a fid, and mutate its slots as required.
     411
     412==== {{version}} (optional)
     413
     414<procedure>(version message)</procedure>
     415
     416The version request corresponds to a 9P {{Tversion}} request. The
     417message is a list of two elements; the first is the maximum message size
     418the client supports, and the second is a protocol version string
     419indicating what version of the 9P protocol is expected (my Linux
     420system sends "9P2000.u")
     421
     422The handler must return a block size which is less than or equal to
     423that requested by the client.
     424
     425The default implementation just returns the block size requested by
     426the client.
     427
     428==== {{disconnect}}
     429
     430<procedure>(disconnect)</procedure>
     431
     432The disconnect handler is called when the underlying connection is
     433closed. There is no message, and the return value is ignored.
     434
     435The default implementation does nothing.
     436
     437==== {{auth}} (optional)
     438
     439<procedure>(auth message bind-fid! reply! error!)</procedure>
     440
     441This corresponds to a 9P {{Tauth}} request. The message is a list of
     442three elements, the fid to bind to the authentication protocol
     443connection, the user name, and the tree name. If the server does not
     444require authentication, it should call the {{error!}} callback with a
     445string such as "No authentication required". If it does require
     446authentication, it should bind the fid to an authentication connection
     447by calling {{bind-fid!}} with a suitable value for the initial state
     448of the authentication protocol, and call {{reply!}} with list
     449containing a single element, a qid of type QTAUTH.
     450
     451The default implementation returns an error indicating that
     452authentication is not required.
     453
     454==== {{attach}}
     455
     456<procedure>(attach message auth-fid-value bind-fid! reply!
     457error!)</procedure>
     458
     459This corresponds to a 9P {{Tattach}} request. The message is a list of
     460four elements, the fid to bind to the root directory, a fid used for
     461authentication, the user name attaching, and the name of the file tree
     462to attach (often just the empty string). If an auth request occurred
     463then {{auth-fid-value}} will be the state of the authentication
     464protocol. {{bind-fid!}} should be called with a value to be the
     465initial state of the root directory fid. {{reply!}} should be called
     466with a list containing a single element, the QID of the root directory
     467if it succeeded, otherwise {{error!}} should be called with an error
     468message string.
     469
     470==== {{flush}} (optional)
     471
     472<procedure>(flush message reply! error!)</procedure>
     473
     474This corresponds to a 9P {{Tflush}} request. The message is a list of
     475one element, the tag of the operation to flush. This is not currently
     476well-supported by the 9p-server implementation, as the tags of
     477operations are not currently exposed to handlers.
     478
     479If the flush succeeds, it should call {{reply!}} with an empty
     480list. If not, it can call {{error!}} with an error string.
     481
     482The default implementation calls its {{reply!}} callback with an empty
     483list.
     484
     485==== {{walk}}
     486
     487<procedure>(walk message parent-fid-value bind-fid! reply! error!)</procedure>
     488
     489This corresponds to a 9P {{Twalk}} request. The message is a list of
     490three elements, those being the fid of the already open parent
     491directory, the fid to bind the located file or directory to, and a
     492list of path components to traverse.
     493
     494{{parent-fid-value}} is the value bound to the parent fid.
     495
     496If the walk operation succeeds, {{bind-fid!}} should be called with
     497the initial state of the new fid, and {{reply!}} called with a list
     498containing a single element, that being the list of QIDs of the
     499traversed directories.
     500
     501If the walk operation fails, {{error!}} should be called with a
     502suitable error string.
     503
     504==== {{open}}
     505
     506<procedure>(open message fid-value reply! error!)</procedure>
     507
     508This corresponds to a 9P {{Topen}} request. The message is a list of
     509two elements, the fid of the file and the requested access
     510mode. {{fid-value}} is the value bound to the fid.
     511
     512If the open operation succeeds, {{reply!}} should be called with a
     513list of two elements, the first being the QID of the newly opened file
     514and the second being the desired I/O block size in bytes.
     515
     516If it fails, {{error!}} should be called with a suitable error string.
     517
     518==== {{create}} (optional)
     519
     520<procedure>(create message fid-value reply! error!)</procedure>
     521
     522This corresponds to a 9P {{Tcreate}} request. The message is a list of
     523four elements, the fid of the directory in which to create the new
     524object, the name, the permissions, and the access mode for the new
     525object. {{fid-value}} is the value bound to the parent directory fid.
     526
     527If the creation succeeds, the fid value should be mutated into the
     528initial state of the new file, and {{reply!}} should be called with a
     529list of two elements, the QID of the new file and the desired I/O
     530block size in bytes.
     531
     532If it fails, {{error!}} should be called with a suitable error string.
     533
     534The default implementation calls {{error!}} with a message stating
     535that creation is not supported.
     536
     537==== {{read}} (optional)
     538
     539<procedure>(read message fid-value reply! error!)</procedure>
     540
     541This corresponds to a 9P {{Tread}} request. The message is a list of
     542three elements, the fid of the file, the offset to read from, and the
     543number of bytes to read. {{fid-value}} is the value bound to the fid.
     544
     545If the read succeeds, {{reply!}} should be called with a list of one
     546argument, that being a u8vector of bytes of the desired length or
     547less.
     548
     549If the read fails, {{error!}} should be called with a suitable error
     550message.
     551
     552The default implementation calls {{error!}} with a message stating
     553that reading is not supported.
     554
     555==== {{write}} (optional)
     556
     557<procedure>(write message fid-value reply! error!)</procedure>
     558
     559This corresponds to a 9P {{Twrite}} request. The message is a list of
     560three elements, the fid of the file, the offset to write to, and the
     561data to write as a u8vector.
     562
     563If the write succeeds, {{reply!}} should be called with a list of a
     564single element, the number of bytes actually written.
     565
     566If the write fails, {{error!}} should be called with a suitable error
     567message.
     568
     569The default implementation calls {{error!}} with a message stating
     570that writing is not supported.
     571
     572==== {{clunk}} (optional)
     573
     574<procedure>(clunk fid-value reply! error!)</procedure>
     575
     576This corresponds to a 9P {{Tclunk}} request. The message consists
     577purely of the fid, so it is not passed to the handler. {{fid-value}}
     578is the value bound to the fid being clunked.
     579
     580If the clunk succeeds, {{reply!}} should be called and passed an empty
     581list.
     582
     583If the clunk fails, {{error!}} should be called with a suitable error
     584message.
     585
     586The default implemention calls {{reply!}} with an empty list.
     587
     588==== {{remove}} (optional)
     589
     590<procedure>(remove fid-value reply! error!)</procedure>
     591
     592This corresponds to a 9P {{Tremove}} request. The message consists
     593purely of the fid, so it is not passed to the handler. {{fid-value}} is
     594the value bound to the fid being removed.
     595
     596If the remove succeeds, {{reply!}} should be called and passed an empty
     597list.
     598
     599If the remove fails, {{error!}} should be called with a suitable error
     600message.
     601
     602The default implemention calls {{error!}} with a message stating that
     603removal is not supported.
     604
     605==== {{stat}} (optional)
     606
     607<procedure>(stat message fid-value reply! error!)</procedure>
     608
     609This corresponsd to a 9P {{Tstate}} request. The message consists
     610purely of the fid, so it is not passed to the handler. {{fid-value}}
     611is the value bound to the fid.
     612
     613If the stat succeeds, {{reply!}} should be called and passed a list of
     614nine elements:
     615
     616* The QID of the file
     617* The permissions of the file
     618* The atime of the file
     619* The mtime of the file
     620* The size of the file
     621* The name of the file
     622* The user name of the file
     623* The group name of the file
     624* The name of the user who last modified the file
     625
     626If it fails, {{error!}} should be called with a suitable error message.
     627
     628The default implementation calls {{error!}} with an error message
     629indicating that stat is not supported.
     630
     631==== {{wstat}} (optional)
     632
     633<procedure>(wstat message fid-value reply! error!)</procedure>
     634
     635This corresponds to a 9P {{Twstat}} request. The message is a list of
     636ten elements:
     637
     638* The fid of the file
     639* The QID of the file
     640* The permissions of the file
     641* The atime of the file
     642* The mtime of the file
     643* The size of the file
     644* The name of the file
     645* The user name of the file
     646* The group name of the file
     647* The name of the user who last modified the file
     648
     649{{fid-value}} is the value bound to the fid.
     650
     651If the wstat succeeds, {{reply!}} should be called with a list of no
     652elements.
     653
     654If if fails, {{error!}} should be called with a suitable error string.
     655
     656The default implementation calls {{error!}} with an error message
     657indicating that wstat is not supported.
     658
     659==== Example
     660
     661Within the 9p egg is a file called 9p-demo-server.scm that runs a 9p
     662server on port 1564, providing a root directory with two read-only
     663files inside.
     664
     665The source code contains the beginnings of an infrastructure for
     666building general virtual filesystems with files whose contents are
     667computed on the fly by Scheme closures.
    313668
    314669=== 9p-lolevel
Note: See TracChangeset for help on using the changeset viewer.