Changes between Version 1 and Version 2 of BoxBackupStoreProtocol


Ignore:
Timestamp:
Aug 10, 2018, 9:14:12 PM (8 months ago)
Author:
chris
Comment:

more protocol docs, formatting

Legend:

Unmodified
Added
Removed
Modified
  • BoxBackupStoreProtocol

    v1 v2  
    1 Application for User Registered Port Number
    2    
    3 Name :
    4 Chris Wilson
    5    
    6 E-mail :
    7 [email protected]
    8        
    9 Protocol Number :
    10 TCP
    11    
    12 Message Formats :
    13 Handshake message:
     1= Store Protocol =
     2
     3This is the protocol used by bbackupd to communicate with bbstored, as described in the application for a registered IANA port number (which was granted: TCP port 4186). However it is normally run on the unregistered port 2201 instead.
     4
     5The protocol is wrapped in TLS, which must be negotiated first. The server verifies the CA that signed the client certificate, and the common name of the client certificate specifies the account number which it is allowed to connect to.
     6
     7The protocol is a binary stream of messages (wrapped in TLS). After the handshake is complete, the client sends a request message to the server, and receives a response message in reply. Although the client could in theory send more requests without waiting for replies, it currently does not.
     8
     9== Code Generator ==
     10
     11The protocol is defined by a machine-readable and human-readable text file, [https://github.com/boxbackup/boxbackup/blob/master/lib/backupstore/BackupProtocol.txt BackupProtocol.txt]. You will likely find additional commands described in that file, which have been added since this document was written. The protocol description is parsed by [https://github.com/boxbackup/boxbackup/blob/master/lib/server/makeprotocol.pl.in makeprotocol.pl] to generate the code for the client and server classes.
     12
     13=== Messages ===
     14
     15Each message is defined by a name, a number of flags, a list of fields (with names and types), and optional constants. For example, the Login message is defined as:
     16
     17{{{
     18Login           2       Command(LoginConfirmed)
     19        int32           ClientID
     20        int32           Flags
     21        CONSTANT        Flags_ReadOnly  1
     22}}}
     23
     24Its message ID (on the wire) is 2. It is a Command message, which means that the client will wait for a reply after sending it, which must be a LoginConfirmed message, otherwise the client will throw an UnexpectedReply exception. It has two fields which are 32-bit integers (ClientID and Flags) and defines a single constant, Flags_ReadOnly, with value 1.
     25
     26=== Message types ===
     27
     28Flags that can be listed on the first line include:
     29
     30* Command(x): the client waits for a reply after sending this, and checks that the type of the reply message is x.
     31* Reply: sent by the server to the client. A message can be used as both a Command and a Reply (e.g. Finished). The same message may be a Reply for multiple Commands (e.g. Success).
     32* EndsConversation: the server stops its read-reply loop after handling such a message.
     33* IsError(Type,SubType): always a reply. The client handles this by raising an exception in CheckReply().
     34* StreamWithCommand: causes the server to call the three-argument form of DoCommand (with the filtered stream as the third argument).
     35
     36=== Message classes ===
     37
     38The generated code includes a unique message class for each message type, listing all of its fields and their types. For example the Login message generates a BackupProtocolLogin message class, which has two private fields (mClientID and mFlags), is constructed with values for them (by the sender), and these values can be retrieved (by the receiver). This message happens to be a Command/Request (a client to server message), so the sender is the client, and the receiver is the server.
     39
     40{{{
     41class BackupProtocolLogin : public BackupProtocolMessage, public BackupProtocolRequest
     42{
     43public:
     44        BackupProtocolLogin();
     45        BackupProtocolLogin(const BackupProtocolLogin &rToCopy);
     46        ~BackupProtocolLogin();
     47        int GetType() const;
     48        enum
     49        {
     50                TypeID = 2
     51        };
     52        enum
     53        {
     54                Flags_ReadOnly = 1
     55        };
     56        std::auto_ptr<BackupProtocolMessage> DoCommand(BackupProtocolReplyable &rProtocol,
     57                BackupStoreContext &rContext) const; // IMPLEMENT THIS
     58
     59        std::auto_ptr<BackupProtocolMessage> DoCommand(BackupProtocolReplyable &rProtocol,
     60                BackupStoreContext &rContext, IOStream& rDataStream) const
     61        {
     62                THROW_EXCEPTION_MESSAGE(CommonException, NotSupported,
     63                        "This command requires no stream parameter");
     64        }
     65        bool HasStreamWithCommand() const { return 0; }
     66        void SetPropertiesFromStreamData(Protocol &rProtocol);
     67        int32_t GetClientID() {return mClientID;}
     68        int32_t GetFlags() {return mFlags;}
     69        BackupProtocolLogin(int32_t ClientID, int32_t Flags);
     70        void WritePropertiesToStreamData(Protocol &rProtocol) const;
     71        void SetClientID(int32_t ClientID) {mClientID = ClientID;}
     72        void SetFlags(int32_t Flags) {mFlags = Flags;}
     73        virtual void LogSysLog(const char *Action) const;
     74        virtual void LogFile(const char *Action, FILE *file) const;
     75        virtual std::string ToString() const;
     76private:
     77        int32_t mClientID;
     78        int32_t mFlags;
     79};
     80}}}
     81
     82=== Client usage ===
     83
     84The client uses the protocol by constructing a SocketStreamTLS (to connect to the server) and then creating a BackupProtocolClient on that stream. The stream should no longer be used directly after that (at least not to read or write bytes).
     85
     86{{{
     87    std::auto_ptr<SocketStream> apConn(new SocketStream);
     88    apConn->Open(Socket::TypeINET, "localhost", 2003);
     89    BackupProtocolClient protocol(apConn);
     90}}}
     91
     92The client then calls Query* methods on the BackupProtocolClient object, and gets a std::auto_ptr<message class> in reply:
     93
     94{{{
     95    std::auto_ptr<TestProtocolSimpleReply> reply(protocol.QuerySimple(41));
     96    TEST_THAT(reply->GetValuePlusOne() == 42);
     97}}}
     98
     99Messages to check the protocol version, login and logout (finish/close the connection) are in no way special, and are defined in exactly the same way as all other messages, except that a command which is defined as EndsConversation will cause the receiver to send a reply (if it is the server) and then disconnect automatically. For example:
     100
     101{{{
     102Finished        4       Command(Finished)       Reply   EndsConversation
     103}}}
     104
     105=== Server usage ===
     106
     107The server side, on handling a new incoming connection, constructs a BackupProtocolServer object, and calls its DoServer method:
     108
     109{{{
     110void BackupProtocolServer::Connection(std::auto_ptr<SocketStream> apStream)
     111{
     112        BackupProtocolServer server(apStream);
     113        BackupStoreContext context;
     114        server.DoServer(context);
     115}
     116}}}
     117
     118It also constructs a BackupStoreContext object, which is passed to every command handler method, and can be used to store global state, such as the identity of the logged-in user and a reference to a BackupFileSystem.
     119
     120The server must also implement the DoCommand method of each message class, for example:
     121
     122{{{
     123std::auto_ptr<BackupProtocolMessage> BackupProtocolLogin::DoCommand(BackupProtocolReplyable &rProtocol, BackupStoreContext &rContext) const
     124{
     125        CHECK_PHASE(Phase_Login)
     126
     127        // Check given client ID against the ID in the certificate certificate
     128        // and that the client actually has an account on this machine
     129        if(mClientID != rContext.GetClientID())
     130        {
     131                BOX_WARNING("Failed login from client ID " <<
     132                        BOX_FORMAT_ACCOUNT(mClientID) << ": "
     133                        "wrong certificate for this account");
     134                return PROTOCOL_ERROR(Err_BadLogin);
     135        }
     136...
     137        // Return success
     138        return std::auto_ptr<BackupProtocolMessage>(new BackupProtocolLoginConfirmed(clientStoreMarker, blocksUsed, blocksSoftLimit, blocksHardLimit));
     139}
     140}}}
     141
     142There are two forms of DoCommand, one for commands that take a stream after their properties (those that send variable length data, such as uploading and downloading files) and those that do not. Only one can be implemented for each command. Whether or not each command takes a stream is defined in BackupProtocol.txt, by the presence of StreamWithCommand on the first line of the command definition. However this is not defined for reply messages (which are not commands). It is documented as a comment on the command. The client must always and only read the stream (by calling ReceiveStream) if the server has sent one (with SendStreamAfterCommand).
     143
     144== Handshake message ==
     145
     146Both sides send a handshake immediately on connection, and then read the other side's handshake. The message format is just a 32-byte character field:
    14147
    15148        char mIdent[32];
    16149
    17 The ident used by both sides is currently "Box-Backup:v=C"
     150The ident used by both sides is currently "Box-Backup:v=C". If either side does not recognise the ident sent by the other, it will disconnect immediately.
     151
     152== Protocol messages ==
     153
     154After handshaking, all messages are protocol messages, of the form:
    18155
    19156Object header:
     
    22159        u_int32_t       mObjType;
    23160        (followed by mObjSize bytes of data)
     161        (followed by a stream, but only if the command's flags include StreamWithCommand)
     162
     163Message Types : 
     164handshake, command, reply, error, stream.
     165
     166Since each command has its own sequence of parameters, given above, you could regard each command as a message type.
     167   
     168Message opcodes :
     169Operation codes are given in brackets after each message description above.
     170     
     171Message Sequences :
     172After handshake, the client sends Command messages to the server, and receives Reply messages (one of which is Error).
     173
     174=== Commands (requests) and replies ===
     175
     176Any command (except Handshake) may receive an Error reply. Otherwise, the expected reply type for each message is defined in BackupProtocol.txt:
     177
     178|| client message || expected response from server ||
     179|| Handshake || Handshake ||
     180|| Version || Version ||
     181|| Login || LoginConfirmed ||
     182|| Finished || Finished ||
     183|| SetClientStoreMarker || Success ||
     184|| GetObject || Success (followed by stream) ||
     185|| MoveObject || Success ||
     186|| GetObjectName || ObjectName ||
     187|| CreateDirectory || Success ||
     188|| ListDirectory || Success + stream ||
     189|| ChangeDirAttributes || Success ||
     190|| DeleteDirectory || Success ||
     191|| UndeleteDirectory || Success ||
     192|| StoreFile + stream || Success ||
     193|| GetFile || Success + stream ||
     194|| SetReplacementFileAttributes + stream || Success ||
     195|| DeleteFile || Success ||
     196|| GetBlockIndexByID || Success + stream ||
     197|| GetBlockIndexByName || Success + stream ||
     198|| GetAccountUsage || AccountUsage ||
     199|| GetIsAlive || IsAlive ||
     200
     201=== Error ===
    24202
    25203Error message (mObjType = 0):
     
    46224        CONSTANT        Err_PatchConsistencyError               14
    47225
     226=== Version ===
     227
    48228Version message (mObjType = 1):
    49229
    50230        int32   Version
    51231
    52 Login Message mObjType = 2):
     232=== Login ===
     233
     234Login Message (mObjType = 2):
    53235
    54236        int32           ClientID
    55237        int32           Flags
    56238        CONSTANT        Flags_ReadOnly  1
     239
     240The successful reply is a LoginConfirmed message.
     241
     242=== LoginConfirmed ===
    57243
    58244LoginConfirmed message (mObjType = 3):
     
    63249        int64           BlocksHardLimit
    64250
     251=== Finished ===
     252
    65253Finished message (mObjType = 4):
    66254
    67255        no data fields
    68256
     257The client sends this as the last command. The server replies with one of the same, and then closes the connection.
     258
     259=== Success ===
     260
    69261Success message (mObjType = 5):
    70262
    71263        int64           ObjectID
    72264
     265The successful response to most commands. The ObjectID field is not always used, and its meaning depends on the command that it's replying to.
     266
     267=== SetClientStoreMarker ===
     268
    73269SetClientStoreMarker message (mObjType = 6):
    74270
    75271        int64           ClientStoreMarker
    76272
    77 GetObject (mObjType = 10)
     273=== GetObject ===
     274
     275GetObject (mObjType = 10):
    78276
    79277        int64           ObjectID
     
    81279        # reply has stream following, if ObjectID != NoObject
    82280
    83 MoveObject (11):
     281=== MoveObject ===
     282
     283MoveObject (mObjType = 11):
    84284
    85285        int64           ObjectID
     
    92292        CONSTANT Flags_AllowMoveOverDeletedObject       2
    93293
    94 GetObjectName (12)
     294=== GetObjectName ===
     295
     296GetObjectName (mObjType = 12):
    95297
    96298        int64           ObjectID
     
    100302        # set ObjectID to ObjectID_DirectoryOnly to only get info on the directory
    101303
    102 ObjectName (13)
     304=== ObjectName ===
     305
     306ObjectName (mObjType = 13):
    103307
    104308        int32           NumNameElements
     
    110314        # a stream of Filename objects follows, if and only if NumNameElements > 0
    111315
    112 CreateDirectory (20)
     316=== CreateDirectory ===
     317
     318CreateDirectory (mObjType = 20):
    113319
    114320        int64           ContainingDirectoryID
     
    117323        # stream following containing attributes
    118324
    119 ListDirectory (21)
     325=== ListDirectory ===
     326
     327ListDirectory (mObjType = 21):
    120328
    121329        int64           ObjectID
     
    132340        CONSTANT        RootDirectory                   1
    133341
    134 ChangeDirAttributes (22)
     342=== ChangeDirAttributes ===
     343
     344ChangeDirAttributes (mObjType = 22):
    135345
    136346        int64           ObjectID
     
    138348        # stream following containing attributes
    139349
    140 DeleteDirectory (23)
    141 
    142         int64           ObjectID
    143 
    144 UndeleteDirectory (24)
    145 
    146         int64           ObjectID
    147 
    148 StoreFile (30)
     350=== DeleteDirectory ===
     351
     352DeleteDirectory (mObjType = 23):
     353
     354        int64           ObjectID
     355
     356=== UndeleteDirectory ===
     357
     358UndeleteDirectory (mObjType = 24):
     359
     360        int64           ObjectID
     361
     362=== StoreFile ===
     363
     364StoreFile (mObjType = 30):
    149365
    150366        int64           DirectoryObjectID
     
    155371        # then send a stream containing the encoded file
    156372
    157 GetFile (31)
     373=== GetFile ===
     374
     375GetFile (mObjType = 31):
    158376
    159377        int64           InDirectory
     
    163381        # (use GetObject to get it in file order)
    164382
    165 SetReplacementFileAttributes (32)
     383=== SetReplacementFileAttributes ===
     384
     385SetReplacementFileAttributes (mObjType = 32):
    166386
    167387        int64           InDirectory
     
    170390        # stream follows containing attributes
    171391
    172 DeleteFile (33)
     392=== DeleteFile ===
     393
     394DeleteFile (mObjType = 33):
    173395
    174396        int64           InDirectory
     
    176398        # will return 0 if the object couldn't be found in the specified directory
    177399
    178 GetBlockIndexByID (34)
    179 
    180         int64           ObjectID
    181 
    182 GetBlockIndexByName (35)
     400=== GetBlockIndexByID ===
     401
     402GetBlockIndexByID (mObjType = 34):
     403
     404        int64           ObjectID
     405
     406=== GetBlockIndexByName ===
     407
     408GetBlockIndexByName (mObjType = 35):
    183409
    184410        int64           InDirectory
    185411
    186 GetAccountUsage (40)
     412=== GetAccountUsage ===
     413
     414GetAccountUsage (mObjType = 40):
    187415
    188416        # no data members
    189417
    190 AccountUsage (41)
     418=== AccountUsage ===
     419
     420AccountUsage (mObjType = 41):
    191421
    192422        int64   BlocksUsed
     
    198428        int32   BlockSize
    199429
    200 GetIsAlive (42)
     430=== GetIsAlive ===
     431
     432GetIsAlive (mObjType = 42):
    201433
    202434        # no data members
    203435
    204 IsAlive (43)
     436A ping/keepalive request.
     437
     438=== IsAlive ===
     439
     440IsAlive (mObjType = 43):
    205441
    206442        # no data members
    207443
    208 
    209 Message Types : 
    210 handshake, command, reply, error, stream.
    211 
    212 Since each command has its own sequence of parameters, given above, you could regard each command as a message type.
    213    
    214 Message opcodes :
    215 Operation codes are given in brackets after each message description above.
    216      
    217 Message Sequences :
    218 After handshake, the client sends Command messages to the server, and receives Reply messages (one of which is Error).
    219 
    220 Any command (except Handshake) may receive an Error reply.
    221 
    222 client message -> expected response from server
    223 Handshake -> Handshake
    224 Version -> Version
    225 Login -> LoginConfirmed
    226 Finished -> Finished
    227 SetClientStoreMarker -> Success
    228 GetObject -> Success (followed by stream)
    229 MoveObject -> Success
    230 GetObjectName -> ObjectName
    231 CreateDirectory -> Success
    232 ListDirectory -> Success + stream
    233 ChangeDirAttributes -> Success
    234 DeleteDirectory -> Success
    235 UndeleteDirectory -> Success
    236 StoreFile + stream -> Success
    237 GetFile -> Success + stream
    238 SetReplacementFileAttributes + stream -> Success
    239 DeleteFile -> Success
    240 GetBlockIndexByID -> Success + stream
    241 GetBlockIndexByName -> Success + stream
    242 GetAccountUsage -> AccountUsage
    243 GetIsAlive -> IsAlive
    244    
    245 Protocol functions :
    246 Management of encrypted files, directories and block indexes (checksums) on an untrusted remote backup server.
    247      
    248 Broadcast or Multicast used ?
    249 no
    250    
    251 How and what for Broadcast or Multicast is used (if used):
    252 Description :
    253 An open source, completely automatic on-line backup system for UNIX and Windows.
    254 
    255 All backed up data is stored on the server in files on a filesystem -- no tape or archive devices are used. The server is trusted only to make files
    256 available when they are required -- all data is encrypted.
    257 
    258 A backup daemon runs on systems to be backed up, and copies encrypted data to the server when it notices changes.
    259 
    260 We need a port number for the server to listen on for requests from backup daemons.
    261    
    262 Name of the port :
    263 Box Backup Store Service
    264 
    265 Short name of the port :
    266 boxbackupstore
     444A ping/keepalive response.