[Libreoffice-commits] online.git: loleaflet/src loolwsd/LoadTest.cpp loolwsd/LOOLProtocol.cpp loolwsd/LOOLProtocol.hpp loolwsd/MasterProcessSession.cpp loolwsd/protocol.txt

Ashod Nakashian ashod.nakashian at collabora.co.uk
Wed Jan 6 09:07:06 PST 2016


 loleaflet/src/core/Socket.js     |   18 +++++++++++++++++-
 loolwsd/LOOLProtocol.cpp         |   21 +++++++++++++++++++++
 loolwsd/LOOLProtocol.hpp         |   16 ++++++++++++++++
 loolwsd/LoadTest.cpp             |   16 ++++++++++++++++
 loolwsd/MasterProcessSession.cpp |   14 ++++++++++++++
 loolwsd/protocol.txt             |   20 ++++++++++++++++++++
 6 files changed, 104 insertions(+), 1 deletion(-)

New commits:
commit 2d385d697e2bced5a23c75aa5bcda43cafc33e61
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Wed Jan 6 12:00:44 2016 -0500

    Protocol versioning added and documented
    
    Change-Id: I6e1df89c7330052bd2d442a42c0b24c8ae4facf6
    Reviewed-on: https://gerrit.libreoffice.org/21168
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index e8d34ef..eaf73a4 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -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) {
diff --git a/loolwsd/LOOLProtocol.cpp b/loolwsd/LOOLProtocol.cpp
index c831abc..0d358c2 100644
--- a/loolwsd/LOOLProtocol.cpp
+++ b/loolwsd/LOOLProtocol.cpp
@@ -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;
diff --git a/loolwsd/LOOLProtocol.hpp b/loolwsd/LOOLProtocol.hpp
index 42e82df..1478713 100644
--- a/loolwsd/LOOLProtocol.hpp
+++ b/loolwsd/LOOLProtocol.hpp
@@ -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);
diff --git a/loolwsd/LoadTest.cpp b/loolwsd/LoadTest.cpp
index 4fdc245..aaa2e3e 100644
--- a/loolwsd/LoadTest.cpp
+++ b/loolwsd/LoadTest.cpp
@@ -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
diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp
index dd66fc2..704b93a 100644
--- a/loolwsd/MasterProcessSession.cpp
+++ b/loolwsd/MasterProcessSession.cpp
@@ -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
diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt
index e9cce86..81a069b 100644
--- a/loolwsd/protocol.txt
+++ b/loolwsd/protocol.txt
@@ -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


More information about the Libreoffice-commits mailing list