Abstract
This document describes giFT's Interface Protocol. This protocol is used by clients to communicate with giFT. Below you'll find all pointers you need to create a client using this protocol. Note that you can also use libgiFT to make a client. (You'd still have to know the protocol commands though, see lib/example.c for a simple example.)
Table of Contents
The interface protocol works by sending specific commands over a socket. The basic syntax of both queries and responses is the same. A complete command block ends with a ;:
COMMAND; |
Some commands require an id. You need to send this as an argument (between parenthesis, no quotes) to the command:
COMMAND(argument); |
Most commands have a set of keys. A key often has a value, in the form of an argument, but this is not required.
COMMAND key1(argument) key2 ; |
COMMAND key1 (argument) key2; |
COMMAND key2 key1 (argument); |
Besides keys (or you could say "as a special key") there are subcommands. A subcommand has a set of keys (with arguments) between braces ({ and }) as a argument. The keys of a subcommand have the same syntax as keys of a normal command. A subcommand can have a normal argument itself too.
COMMAND key1 SUBCOMMAND (argument) { subkey1 subkey2(argument) } ; |
A subcommand can even have a subcommand itself (that would make it a subsubcommand). Information about how you should parse that is in Section 1.5.3.
As an overview, here are the definitions of all used objects (bottom-up). The *, + and ? are used a special chars, and have the same meaning as they would have in a regular expression [1] . Keep in mind, (sub)commands and keys are case insensitive, and order and whitespace don't matter (except inside an argument). Of course, you must use the command, subcommand or key before its argument. The only time you'll actually need whitespace is when the command is directly followed by a key.
key, SUBCOMMAND and COMMAND are replaceable by any string matching \w[\d\w_]* [2] . An argument can contain any character, but (, ), {, }, ; and \ must be escaped.
Whitespace outside arguments is not important. All whitespace is treated the same, namely as a single space (' '). You can consider whitespace as a 'token-seperator'.
Order isn't important either, it doesn't really matter in what the order is of the keys, and, less trivial, you can send the argument and the set of keys (for subcommands) in any order.
Time for an example. This:
SEARCH(4) query (foo bar) realm (audio) META { bitrate(>=192)foo(bla) } (c owns me) bla ( blum! ) ; |
SEARCH (4) query (foo bar) realm (audio) META (c owns me) { bitrate (>=192) foo (bla) } bla ( blum! ) ; |
By this time, you should have asked yourself "But what if I, for example, want to include a ')' in an argument?", but even if you didn't, here's what:
Each argument in the protocol must be encoded by escaping (, ), {, }, ; and \ to ensure that only cleanly parsable text is present. Escaping in this context means that you must put \ directly for the special character. An example:
COMMAND key(arg\(ument\)) SUBCOMMAND (/\{dude\}\\) subkey(\;\;\;) ; |
(SUB)COMMAND.
*, +, ?. 'meta-characters'[1], don't include these.
replaceable text
optional subcommands/arguments/attributes
Data sent by the client |
Data sent by the server |
Data that can be sent by both the client and the server |
|
Event identifiers are requested by the client (with a few exceptions) and will be considered session-specific. The response of the server will use the same id as the client requested. This completely eliminates the need to wait on the servers event response, and consequently the command completely. All session-specific id's must be unique (to that session) and must not overlap. This means you'll have to keep track of all used ids, the ones specified by your client, and the ones giFT uses,
In order to take advantage of the event identifiers (and therefore multiple events per socket), giFT clients are expected to register this as an active single-socket session with the daemon. This is done via the ATTACH request, described below:
ATTACH client(client) version(client version) profile(profile) ; |
ATTACH server(server) version(server version) ; |
You may also request an explicit detach from the session which will result in the connections closure from the server. Please note that this request is ignored if the session is not attached. This request is simply:
DETACH; |
The most basic way of finding files, is just a plain search. This is done by using the SEARCH (as you already guessed). Valid options for a search are as follows:
SEARCH (session-id) query (tokens) exclude (tokens) realm (realm) META { key_name (value) } ; |
The BROWSE command carries the same options and basic structure as the SEARCH command. The server may safely treat both searches and browses identically except when presenting the request to the protocol, which should assume these operations are quite different. The data received from the querying requests is identical in form.
The common use of BROWSE is to specify a protocol specific identifier for a user as the query. As with SEARCH, you can limit the request by using keys as realm, for example.
LOCATE also follows the same basic structure as the SEARCH command. The main difference is its options. LOCATE only specifies query.
The purpose of LOCATE is to find different sources for the same file. Use a file hash as its query.
The server replies to SEARCH, BROWSE and LOCATE with the following:
ITEM (session-id) user (username) node (server) availability (availability) size (filesize) url (protocol specific url) file (path and filename) mime (mime-type) hash (hash) META { name (value) } ; |
ITEM(session-id); |
SEARCH(session-id) action(cancel); |
The META subcommand will contain a set of keys that are applicable for this type of file (if known). Those keys are not hardcoded, so you'll have to find a creative way of parsing those. You could for example hardcode a few keys certain mime categories such as 'artist' and 'title' for audio/*, and match meta keys that contain those values. Just an idea.
When initiating transfers you must send all sources that are to be used in the form described below. You should note that a download will be instantiated when the first source is seen. Protocols which do not support hashes will always create a new transfer when an ADDSOURCE command is given.
ADDSOURCE user (username) hash (hash) size (filesize) url (url) save (save) ; |
The protocol uses one generic format for new transfers, ADDdir, where dir is the direction of the transfer, namely DOWNLOAD or UPLOAD. On ATTACH;, the ADDdirs for all current transfers will be dumped.
ADDdir (session-id) hash (hash) state (state) transmit (transmited) size (filesize) file (save) shared (shared) SOURCE* { user (username) url (url) statusgrl (status status (protocol status) start (chunk start) transmit (chunk transmit) total (chunk total) } ; |
Reporting of a transfer's progress will be done in a similar way for uploads and downloads. In fact, the format looks a lot like ADDdir's, only with a minor addition. The command for reports is CHGdir (That means, CHGUPLOAD or CHGDOWNLOAD. Please note that CHGdir will only be sent when something actually changed. By default it will not be sent more than once every second.
CHGdir(session-id) throughput (throughput) elapsed (elapsed) ... [ADDdir's body] ; |
To cancel a transfer (both uploads and downloads):
TRANSFER(session-id) action (action) ; |
For downloads, you can also cancel only one source. This is done with the DELSOURCE command:
DELSOURCE(session-id) url (url) ; |
To manipulate the shares index you may use:
SHARE action (action) ; |
SHARE action (action) status (action status) ; |
To see all the files you share (according to giFT, not to the protocols), you can use this nifty oneliner:
SHARES(session-id); |
ITEM (session-id) path (path and filename) size (filesize) mime (mime-type) hash (hash) META { name (value) } ; |
Request stats dump explicitly:
STATS; |
STATS protocol* { users (users) files (files) size (total size) ; |
To shutdown giFT, you can use the QUIT command:
QUIT; |