Protocol versioning added and documented

Change-Id: I6e1df89c7330052bd2d442a42c0b24c8ae4facf6
Reviewed-on: https://gerrit.libreoffice.org/21168
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
This commit is contained in:
Ashod Nakashian 2016-01-06 12:00:44 -05:00 committed by Ashod Nakashian
parent 9285f50c6b
commit 2d385d697e
6 changed files with 104 additions and 1 deletions

View file

@ -3,6 +3,8 @@
*/
L.Socket = {
ProtocolVersionNumber: '0.1',
connect: function (map) {
try {
this.socket = new WebSocket(map.options.server);
@ -44,6 +46,10 @@ L.Socket = {
},
_onOpen: function () {
// Always send the protocol version number.
// TODO: Move the version number somewhere sensible.
this.socket.send('loolclient ' + this.ProtocolVersionNumber);
var msg = 'load url=' + this._map.options.doc;
if (this._map._docLayer) {
// we are reconnecting after a lost connection
@ -85,7 +91,17 @@ L.Socket = {
textMsg = String.fromCharCode.apply(null, imgBytes.subarray(0, index));
}
if (!textMsg.startsWith('tile:') && !textMsg.startsWith('renderfont:')) {
if (textMsg.startsWith('loolserver ')) {
// This must be the first message.
if (this._map._docLayer) {
this.fire('error', {msg: 'Unexpected loolserver message.'});
}
// TODO: For now we expect perfect match.
if (textMsg.substring(11) !== this.ProtocolVersionNumber) {
this.fire('error', {msg: 'Unsupported server version.'});
}
}
else if (!textMsg.startsWith('tile:') && !textMsg.startsWith('renderfont:')) {
// log the tile msg separately as we need the tile coordinates
L.Log.log(textMsg, L.INCOMING);
if (imgBytes !== undefined) {

View file

@ -23,6 +23,27 @@ using Poco::StringTokenizer;
namespace LOOLProtocol
{
std::tuple<signed, signed, std::string> ParseVersion(const std::string& version)
{
signed major = -1;
signed minor = -1;
std::string patch;
StringTokenizer firstTokens(version, ".", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
if (firstTokens.count() > 0)
{
major = std::stoi(firstTokens[0]);
StringTokenizer secondTokens(firstTokens[1], "-", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
minor = std::stoi(secondTokens[0]);
if (secondTokens.count() > 1)
patch = secondTokens[1];
}
return std::make_tuple(major, minor, patch);
}
bool getTokenInteger(const std::string& token, const std::string& name, int& value)
{
size_t nextIdx;

View file

@ -62,6 +62,22 @@ namespace LOOLProtocol
TILE,
};
// Protocol Version Number.
// See protocol.txt.
constexpr unsigned ProtocolMajorVersionNumber = 0;
constexpr unsigned ProtocolMinorVersionNumber = 1;
inline
std::string GetProtocolVersion()
{
return std::to_string(ProtocolMajorVersionNumber) + '.'
+ std::to_string(ProtocolMinorVersionNumber);
}
// Parse a string into a version tuple.
// Negative numbers for error.
std::tuple<signed, signed, std::string> ParseVersion(const std::string& version);
bool getTokenInteger(const std::string& token, const std::string& name, int& value);
bool getTokenString(const std::string& token, const std::string& name, std::string& value);
bool getTokenKeyword(const std::string& token, const std::string& name, const std::map<std::string, int>& map, int& value);

View file

@ -115,6 +115,20 @@ public:
#endif
response = getFirstLine(buffer, n);
}
else if (tokens[0] == "loolclient")
{
const auto versionTuple = ParseVersion(tokens[1]);
if (std::get<0>(versionTuple) != ProtocolMajorVersionNumber ||
std::get<1>(versionTuple) != ProtocolMinorVersionNumber)
{
const std::string error = "error: cmd=loolclient kind=badversion";
_ws.sendFrame(error.c_str(), error.size());
break;
}
const auto version = "loolserver " + GetProtocolVersion();
_ws.sendFrame(version.c_str(), version.size());
}
if (response.find("status:") == 0)
{
parseStatus(response, _type, _numParts, _currentPart, _width, _height);
@ -203,6 +217,8 @@ private:
thread.start(output);
sendTextFrame(ws, "loolclient " + GetProtocolVersion());
if (document[0] == '/')
sendTextFrame(ws, "load " + document);
else

View file

@ -81,6 +81,20 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length)
const std::string firstLine = getFirstLine(buffer, length);
StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
if (tokens[0] == "loolclient")
{
const auto versionTuple = ParseVersion(tokens[1]);
if (std::get<0>(versionTuple) != ProtocolMajorVersionNumber ||
std::get<1>(versionTuple) != ProtocolMinorVersionNumber)
{
sendTextFrame("error: cmd=loolclient kind=badversion");
return false;
}
sendTextFrame("loolserver " + GetProtocolVersion());
return true;
}
if (haveSeparateProcess())
{
// Note that this handles both forwarding requests from the client to the child process, and

View file

@ -11,6 +11,16 @@ tiles proactively (guessing what the client might need). Etc.
client -> server
================
loolclient <major.minor[-patch]>
Upon connection, a client must announce the version number it supports.
Major: an integer that must always match between client and server,
otherwise there are no guarantees of any sensible
compatibility. This is bumped when API changes.
Minor: an integer is more flexible and is at the discretion of either party.
Security fixes that do not alter the API would bump the minor version number.
Patch: an optional string that is informational.
canceltiles
All outstanding tile messages from the client to the server are
@ -109,6 +119,16 @@ partpagerectangles
server -> client
================
loolserver <major.minor[-patch]>
Upon connection, the server must announce the version number it supports.
Major: an integer that must always match between client and server,
otherwise there are no guarantees of any sensible
compatibility. This is bumped when API changes.
Minor: an integer is more flexible and is at the discretion of either party.
Security fixes that do not alter the API would bump the minor version number.
Patch: an optional string that is informational.
downloadas: jail=<jail directory> dir=<a tmp dir> name=<name> port=<port>
The client should then request http://server:port/jail/dir/name in order to download