Subversion Repositories Spectranet

[/] [trunk/] [tnfs/] [tnfs-protocol.txt] - Rev 178

Go to most recent revision | Compare with Previous | Blame | View Log

The TNFS protocol
=================

Rationale
---------
Protocols such as NFS (unix) or SMB (Windows) are overly complex for 8 bit
systems. While NFS is well documented, it's a complex RPC based protocol.
SMB is much worse. It is also a complex RPC based protocol, but it's also
proprietary, poorly documented, and implementations differ so much that
to get something that works with a reasonable subset of SMB would add a
great deal of unwanted complexity. The Samba project has been going for 
/years/ and they still haven't finished making it bug-for-bug compatible with
the various versions of Windows!

At the other end, there's FTP, but FTP is not great for a general file
system protocol for 8 bit systems - it requires two TCP sockets for
each connection, and some things are awkward in ftp, even if they work.

So instead, TNFS provides a straightforward protocol that can easily be
implemented on most 8 bit systems. It's designed to be a bit better than
FTP for the purpose of a filesystem, but not as complex as the "big" network
filesystem protocols like NFS or SMB.

For a PC, TNFS can be implemented using something like FUSE (no, not the
Spectrum emulator, but the Filesystem In Userspace project). This is
at least available for most things Unixy (Linux, OS X, some of the BSDs),
and possibly by now for Windows also.

Security
--------
This is not intended to be a proper, secure network file system. If you're
storing confidential files on your Speccy, you're barmy :) Encryption,
for example, is not supported. However, servers that may be exposed to the 
internet should be coded in such a way they won't open up the host system 
to exploits.

Operations supported
====================
These generally follow the POSIX equivalents. Entries with a * are mandatory
for servers to support.

Connection management
---------------------
mount - Connect to a TNFS filesystem *
umount - Disconnect from a TNFS filesystem *

Directories
-----------
opendir - Opens a directory for reading *
readdir - Reads a directory entry *
closedir - Closes the directory *
chdir - Changes the working directory
rmdir - Removes a directory
mkdir - Creates a directory

Files
-----
open - Opens a file *
read - reads from an open file *
write - writes to an open file
close - closes a file *
stat - gets information about a file *
lseek - set the position in the file where the next byte will be read/written
chmod - change file access
unlink - remove a file

Note: Not all servers have to support all operations - for example, a server
on a Spectrum with a microdrive, or +3 floppy won't support
chdir/mkdir/rmdir and will only support limited options for chmod. But
a BBC Micro with ADFS would support chdir/mkdir/readdir.

The directory delimiter in all cases is a "/". A server running on a filesystem
that has a different delimiter will have to translate, for example,
on a BBC with ADFS, the / would need to be translated to a "." for the
underlying OS operation. 

Protocol "on the wire"
======================

The lowest common denominator is TNFS over UDP. UDP is the 'mandatory'
one because it demands the least of possibly small TCP/IP stacks which may
have limited resources for TCP sockets. All TNFS servers must
support the protocol on UDP port 16384. TCP is optional.

Each datagram has a header. The header is formatted the same way for all
datagrams.

Bytes 0,1       Connection ID (ignored for client's "mount" command)
Byte  2         Sequence/retry number
Byte  3         Command

The connection ID is to add extra identifying information, since two machines
may share an IP address due to NAT, and it provides a limited amount of
anti-spoofing.

Byte 2 is a sequence or retry number. It is used as a sequence number
for multi-datagram operations, such as reading or writing a file or
reading a directory. For single datagram operations such as an "open"
command, it is the retry number. If the client resends the request due
to not receiving a timely response, it increments this number. That way
if a server gets two requests, because it did reply and the reply got
lost, the second request is a repeat of the first simply by examining
the sequence byte. This number always starts at 0x00 for a new operation.

The last byte is the command.

The remaining data in the datagram are specific to each command.

As can be seen from this very simple wire protocol, TNFS is not designed
for confidentiality.

TNFS command datagrams
======================

Logging on and logging off a TNFS server - MOUNT and UMOUNT commands.
---------------------------------------------------------------------

MOUNT - Command ID 0x00
-----------------------

Format:
Standard header followed by:
Bytes 4+: NULL terminated string: mount location
          NULL terminated string: user id (optional - NULL if no user id)
          NULL terminated string: password (optional - NULL if no passwd)

The sequence number is the requested version of the TNFS protocol.
Currently, this should be set to 0x0000

Example:

To mount /home/tnfs on the server, with user id "example" and password of
"password":
0x0000 0x00 0x00 /home/tnfs 0x00 example 0x00 password 0x00

To mount "a:" anonymously:
0x0000 0x00 0x00 a: 0x00 0x00 0x00

The server responds with the standard header. The session ID is set to 
a nonzero value if the MOUNT command succeeded. If it failed, the session ID
field is set to zero, and byte 6 is set to the error code.

Example: A successful MOUNT command was carried out:

0xBEEF 0x00 0x00

Example: A failed MOUNT command with error 1F
0x0000 0x00 0x00 0x1F

UMOUNT - Command ID 0x01
------------------------

Format:
Standard header only, containing the connection ID to terminate, 0x00 as
the sequence number, and 0x01 as the command.

Example:
To UMOUNT the filesystem mounted with id 0xBEEF:

0xBEEF 0x00 0x01

The server responds with the standard header and a return code as byte 4.
The return code is 0x00 for OK. Example:

0xBEEF 0x00 0x01 0x00

On error, byte 4 is set to the error code, for example, for error 0x1F:

0xBEEF 0x00 0x01 0x1F

DIRECTORIES - Opening, Reading and Closing
==========================================
Don't confuse this with the ability of having a directory heirachy. Even
servers (such as a +3 with a floppy) that don't have heirachical filesystems
must support cataloguing a disc, and cataloguing a disc requires opening,
reading, and closing the catalogue. It's the only way to do it!

OPENDIR - Open a directory for reading - Command ID 0x02
--------------------------------------------------------

Format:
Standard header followed by a null terminated path. "." indicates
current directory. ".." indicates up one level. The path delimiter is always
a "/". Servers whose underlying file system uses other delimiters, such
as Acorn ADFS, should translate. Note that any recent version of Windows
understands "/" to be a path delimiter, so a Windows server does not need
to translate a "/" to a "\".

Example:
0xBEEF 0x00 0x02 . 0x00 - Open current directory
0xBEEF 0x00 0x02 /home/tnfs 0x00 - Open absolute path "/home/tnfs"
0xBEEF 0x00 0x02 ../../foo 0x00 - Open relative path "../../foo"

The server responds with the standard header, with byte 4 set to the
return code which is 0x00 for success, and if successful, byte 5 
is set to the directory handle.

Example:
0xBEEF 0x00 0x02 0x00 0x04 - Successful, handle is 0x04
0xBEEF 0x00 0x02 0x1F - Failed with code 0x1F

READDIR - Reads a directory entry - Command ID 0x03
---------------------------------------------------

Format:
Standard header plus directory handle.

Example:
0xBEEF 0x00 0x03 0x04 - Read an entry with directory handle 0x04

The server responds with the standard header, with the sequence number
set to the directory entry number. Following the standard header is
a NULL terminated string, which is the directory entry. Example:
0xBEEF 0x00 0x03 . 0x00 - Directory entry for the current working directory
0xBEEF 0x01 0x03 .. 0x00 - Directory entry for parent
0xBEEF 0x02 0x03 foo 0x00 - File named "foo"

If the end of directory is reached, or other error is reached, the
header is sent as above, but byte 4 is set to 0x00 and byte 5 is set to
the code (either EOF or an error):
0xBEEF 0x03 0x03 0x00 0x01 - EOF
0xBEEF 0x04 0x03 0x00 0x1F - Error code 0x1F

CLOSEDIR - Close a directory handle - Command ID 0x04
-----------------------------------------------------

Format:
Standard header plus directory handle.

Example:
0xBEEF 0x00 0x04

The server responds with the standard header, with byte 4 set to the
return code which is 0x00 for success, or something else for an error.
Example:
0xBEEF 0x00 0x04 0x00 - Close operation succeeded.
0xBEEF 0x00 0x04 0x1F - Close failed with error code 0x1F

Go to most recent revision | Compare with Previous | Blame | View Log