[Libreoffice-commits] online.git: 6 commits - loolwsd/LoadTest.cpp loolwsd/LOOLSession.cpp loolwsd/LOOLSession.hpp loolwsd/LOOLWSD.cpp loolwsd/protocol.txt loolwsd/TileCache.cpp loolwsd/TileCache.hpp
Tor Lillqvist
tml at collabora.com
Thu May 28 06:49:43 PDT 2015
loolwsd/LOOLSession.cpp | 30 +++++++-------------
loolwsd/LOOLSession.hpp | 21 ++++++++------
loolwsd/LOOLWSD.cpp | 30 ++++++++++++--------
loolwsd/LoadTest.cpp | 28 +++++++++++++-----
loolwsd/TileCache.cpp | 71 ------------------------------------------------
loolwsd/TileCache.hpp | 3 --
loolwsd/protocol.txt | 9 ++++++
7 files changed, 70 insertions(+), 122 deletions(-)
New commits:
commit f6a00edbeeed69d66d36e39df1fd8abc44bd7605
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 16:42:38 2015 +0300
Use shared_ptr to the WebSockets for increased robustness
Why did I wait so long to do this? This is obviously the right thing to do, I
hope, and has a very significant impact on the robustness of the server...
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index 3221dd4..9bbca5b 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -71,12 +71,12 @@ using Poco::Util::Application;
const std::string LOOLSession::jailDocumentURL = "/user/thedocument";
-LOOLSession::LOOLSession(WebSocket& ws, Kind kind) :
+LOOLSession::LOOLSession(std::shared_ptr<WebSocket> ws, Kind kind) :
_kind(kind),
- _ws(&ws),
+ _ws(ws),
_docURL("")
{
- std::cout << Util::logPrefix() << "LOOLSession ctor this=" << this << " " << _kind << " ws=" << _ws << std::endl;
+ std::cout << Util::logPrefix() << "LOOLSession ctor this=" << this << " " << _kind << " ws=" << _ws.get() << std::endl;
}
LOOLSession::~LOOLSession()
@@ -104,11 +104,11 @@ std::condition_variable MasterProcessSession::_availableChildSessionCV;
Poco::Random MasterProcessSession::_rng;
std::mutex MasterProcessSession::_rngMutex;
-MasterProcessSession::MasterProcessSession(WebSocket& ws, Kind kind) :
+MasterProcessSession::MasterProcessSession(std::shared_ptr<WebSocket> ws, Kind kind) :
LOOLSession(ws, kind),
_childId(0)
{
- std::cout << Util::logPrefix() << "MasterProcessSession ctor this=" << this << " ws=" << _ws << std::endl;
+ std::cout << Util::logPrefix() << "MasterProcessSession ctor this=" << this << " ws=" << _ws.get() << std::endl;
}
MasterProcessSession::~MasterProcessSession()
@@ -590,12 +590,12 @@ void MasterProcessSession::forwardToPeer(const char *buffer, int length)
peer->_ws->sendFrame(buffer, length, WebSocket::FRAME_BINARY);
}
-ChildProcessSession::ChildProcessSession(WebSocket& ws, LibreOfficeKit *loKit) :
+ChildProcessSession::ChildProcessSession(std::shared_ptr<WebSocket> ws, LibreOfficeKit *loKit) :
LOOLSession(ws, Kind::ToMaster),
_loKit(loKit),
_loKitDocument(NULL)
{
- std::cout << Util::logPrefix() << "ChildProcessSession ctor this=" << this << " ws=" << _ws << std::endl;
+ std::cout << Util::logPrefix() << "ChildProcessSession ctor this=" << this << " ws=" << _ws.get() << std::endl;
}
ChildProcessSession::~ChildProcessSession()
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 64a2dae..2d780d7 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -46,7 +46,7 @@ public:
virtual bool getStatus(const char *buffer, int length) = 0;
protected:
- LOOLSession(Poco::Net::WebSocket& ws, Kind kind);
+ LOOLSession(std::shared_ptr<Poco::Net::WebSocket> ws, Kind kind);
virtual ~LOOLSession();
static const std::string jailDocumentURL;
@@ -65,7 +65,7 @@ protected:
// In the master process, the websocket to the LOOL client or the jailed child process. In a
// jailed process, the websocket to the parent.
- Poco::Net::WebSocket *_ws;
+ std::shared_ptr<Poco::Net::WebSocket> _ws;
// In the master, the actual URL. In the child, the copy inside the chroot jail.
std::string _docURL;
@@ -91,7 +91,7 @@ inline std::basic_ostream<charT, traits> & operator <<(std::basic_ostream<charT,
class MasterProcessSession final : public LOOLSession, public std::enable_shared_from_this<MasterProcessSession>
{
public:
- MasterProcessSession(Poco::Net::WebSocket& ws, Kind kind);
+ MasterProcessSession(std::shared_ptr<Poco::Net::WebSocket> ws, Kind kind);
virtual ~MasterProcessSession();
virtual bool handleInput(char *buffer, int length) override;
@@ -146,7 +146,7 @@ private:
class ChildProcessSession final : public LOOLSession
{
public:
- ChildProcessSession(Poco::Net::WebSocket& ws, LibreOfficeKit *loKit);
+ ChildProcessSession(std::shared_ptr<Poco::Net::WebSocket> ws, LibreOfficeKit *loKit);
virtual ~ChildProcessSession();
virtual bool handleInput(char *buffer, int length) override;
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 34aa2e4..fa4d386 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -139,7 +139,7 @@ public:
{
try
{
- WebSocket ws(request, response);
+ std::shared_ptr<WebSocket> ws(new WebSocket(request, response));
std::shared_ptr<MasterProcessSession> session;
@@ -157,11 +157,11 @@ public:
// the client).
int flags;
int n;
- ws.setReceiveTimeout(0);
+ ws->setReceiveTimeout(0);
do
{
char buffer[100000];
- n = ws.receiveFrame(buffer, sizeof(buffer), flags);
+ n = ws->receiveFrame(buffer, sizeof(buffer), flags);
if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
{
@@ -178,7 +178,7 @@ public:
{
char largeBuffer[size];
- n = ws.receiveFrame(largeBuffer, size, flags);
+ n = ws->receiveFrame(largeBuffer, size, flags);
if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
{
if (!session->handleInput(largeBuffer, n))
@@ -579,6 +579,12 @@ namespace
#if ENABLE_DEBUG
if (geteuid() == 0 && getuid() == 0)
{
+#ifdef __linux
+ // Argh, awful hack
+ if (capability == CAP_FOWNER)
+ return;
+#endif
+
// Running under sudo, probably because being debugged? Let's drop super-user rights.
LOOLWSD::runningAsRoot = true;
if (LOOLWSD::uid == 0)
@@ -664,11 +670,11 @@ int LOOLWSD::childMain()
cs.setTimeout(0);
HTTPRequest request(HTTPRequest::HTTP_GET, LOOLWSD::CHILD_URI);
HTTPResponse response;
- WebSocket ws(cs, request, response);
+ std::shared_ptr<WebSocket> ws(new WebSocket(cs, request, response));
ChildProcessSession session(ws, loKit);
- ws.setReceiveTimeout(0);
+ ws->setReceiveTimeout(0);
std::string hello("child " + std::to_string(_childId));
session.sendTextFrame(hello);
@@ -678,7 +684,7 @@ int LOOLWSD::childMain()
do
{
char buffer[1024];
- n = ws.receiveFrame(buffer, sizeof(buffer), flags);
+ n = ws->receiveFrame(buffer, sizeof(buffer), flags);
if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
if (!session.handleInput(buffer, n))
commit 295bc3c42f172cdfb6b4602d04571608ec5ac159
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 16:16:02 2015 +0300
Add some variation to the time each doc is tested
diff --git a/loolwsd/LoadTest.cpp b/loolwsd/LoadTest.cpp
index 3539c45..7b7ca38 100644
--- a/loolwsd/LoadTest.cpp
+++ b/loolwsd/LoadTest.cpp
@@ -153,21 +153,20 @@ class Client: public Runnable
public:
Client(LoadTest& app) :
- _app(app)
+ _app(app),
+ _g(_rd())
{
}
void run() override
{
std::vector<std::string> uris(_app.getDocList());
- std::random_device rd;
- std::mt19937 g(rd());
- std::shuffle(uris.begin(), uris.end(), g);
+ std::shuffle(uris.begin(), uris.end(), _g);
if (uris.size() > _app.getNumDocsPerClient())
uris.resize(_app.getNumDocsPerClient());
while (!clientDurationExceeded())
{
- std::shuffle(uris.begin(), uris.end(), g);
+ std::shuffle(uris.begin(), uris.end(), _g);
for (auto i : uris)
{
if (clientDurationExceeded())
@@ -222,11 +221,14 @@ private:
int y = 0;
const int DOCTILESIZE = 5000;
+ std::uniform_int_distribution<> dis(0, 20);
+ int extra = dis(_g);
+
// Exercise the server with this document for some minutes
- while (!documentStartTimestamp.isElapsed(20 * Timespan::SECONDS) && !clientDurationExceeded())
+ while (!documentStartTimestamp.isElapsed((20 + extra) * Timespan::SECONDS) && !clientDurationExceeded())
{
int x = 0;
- while (!documentStartTimestamp.isElapsed(20 * Timespan::SECONDS) && !clientDurationExceeded())
+ while (!documentStartTimestamp.isElapsed((20 + extra) * Timespan::SECONDS) && !clientDurationExceeded())
{
sendTextFrame(ws,
"tile part=0 width=256 height=256 "
@@ -239,7 +241,7 @@ private:
break;
}
y = ((y + 1) % ((output._height-1)/DOCTILESIZE + 1));
- Thread::sleep(1000);
+ Thread::sleep(200);
}
Thread::sleep(10000);
@@ -257,6 +259,9 @@ private:
LoadTest& _app;
Timestamp _clientStartTimestamp;
+
+ std::random_device _rd;
+ std::mt19937 _g;
};
LoadTest::LoadTest() :
commit 7245c795d2eed5f3afc5ab7c583c7a5bbfa8adc4
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 15:29:04 2015 +0300
Add one more line of (ifdeffed-out) debug ouput
diff --git a/loolwsd/LoadTest.cpp b/loolwsd/LoadTest.cpp
index bac83bd..3539c45 100644
--- a/loolwsd/LoadTest.cpp
+++ b/loolwsd/LoadTest.cpp
@@ -110,6 +110,13 @@ public:
char largeBuffer[size];
n = _ws.receiveFrame(largeBuffer, size, flags);
+
+#if 0
+ std::cout <<
+ Util::logPrefix() <<
+ "Client got " << n << " bytes: " << getAbbreviatedMessage(largeBuffer, n) <<
+ std::endl;
+#endif
// We don't actually need to do anything with the buffer in this program. We
// only parse status: messages and they are not preceded by nextmessage:
// messages.
commit 73273eb02790fae26824dbe9d35fc2faedfc282f
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 15:25:08 2015 +0300
Also let the nextmessage: from a child process be forwarded to the client
The loadtest program needs it as it, too, uses Poco, which currently does not
have an API to receive an arbitrarily large WebSocket message.
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 201210e..34aa2e4 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -165,6 +165,11 @@ public:
if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
{
+ if (!session->handleInput(buffer, n))
+ n = 0;
+ }
+ if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
+ {
std::string firstLine = getFirstLine(buffer, n);
StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
@@ -180,11 +185,6 @@ public:
n = 0;
}
}
- else
- {
- if (!session->handleInput(buffer, n))
- n = 0;
- }
}
}
while (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt
index b500073..10aa581 100644
--- a/loolwsd/protocol.txt
+++ b/loolwsd/protocol.txt
@@ -69,6 +69,15 @@ tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<
The parameters from the corresponding 'tile' command.
+nextmessage: size=<byteSize>
+
+ <byteSize> is the size, in bytes, of the next message, in case it
+ is "large" (in practise, nextmessage: messages precede each tile:
+ message). Can be ignored by clients using an API that can read
+ arbitrarily large buffers from a WebSocket (like JavaScript), but
+ must be handled by clients that cannot (like those using Poco
+ 1.6.0).
+
Each LOK_CALLBACK_FOO_BAR callback causes a corresponding message to
the client, consisting of the FOO_BAR part in lowercase, without
underscore, followed by a colon, space and the callback payload. For
commit d0dbc5e1dde20070ac2c5390bca69fa3966986b4
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 14:53:55 2015 +0300
Send a nextmessage: message also preceding a tile: message from the cache
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index e36cc39..3221dd4 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -488,6 +488,8 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni
cachedTile->read(output.data() + pos, size);
cachedTile->close();
+ sendTextFrame("nextmessage: size=" + std::to_string(output.size()));
+
sendBinaryFrame(output.data(), output.size());
return;
commit 09b261d57bd4fe94e6f6622fbf980a5203a77eaa
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu May 28 14:51:08 2015 +0300
Handle LOK_CALLBACK_DOCUMENT_SIZE_CHANGED even better
Just call the getStatus() function directly in the child process, which will
always cause a complete status: message to be sent to the client. No
documentsizechanged: messages now sent to the client at all.
diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp
index f5f7e36..e36cc39 100644
--- a/loolwsd/LOOLSession.cpp
+++ b/loolwsd/LOOLSession.cpp
@@ -134,7 +134,7 @@ bool MasterProcessSession::handleInput(char *buffer, int length)
// Note that this handles both forwarding requests from the client to the child process, and
// forwarding replies from the child process to the client. Or does it?
- // Snoop at tile:, status: and documentsizechanged: messages and (re-)cache them
+ // Snoop at tile: and status: messages and (re-)cache them
auto peer = _peer.lock();
if (_kind == Kind::ToPrisoner && peer && peer->_tileCache)
{
@@ -159,16 +159,6 @@ bool MasterProcessSession::handleInput(char *buffer, int length)
assert(firstLine.size() == static_cast<std::string::size_type>(length));
peer->_tileCache->saveStatus(firstLine);
}
- else if (tokens[0] == "documentsizechanged:")
- {
- std::string statusMessage;
- assert(firstLine.size() == static_cast<std::string::size_type>(length));
- if (peer->_tileCache->updateSizeInStatus(firstLine, statusMessage))
- {
- forwardToPeer(statusMessage.c_str(), statusMessage.size());
- return true;
- }
- }
}
forwardToPeer(buffer, length);
@@ -742,7 +732,7 @@ extern "C"
srv->sendTextFrame("searchnotfound: " + std::string(pPayload));
break;
case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
- srv->sendTextFrame("documentsizechanged: " + std::string(pPayload));
+ srv->getStatus("", 0);
break;
case LOK_CALLBACK_SET_PART:
srv->sendTextFrame("setpart: " + std::string(pPayload));
diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp
index 4d7dc06..64a2dae 100644
--- a/loolwsd/LOOLSession.hpp
+++ b/loolwsd/LOOLSession.hpp
@@ -43,6 +43,8 @@ public:
void sendTextFrame(const std::string& text);
+ virtual bool getStatus(const char *buffer, int length) = 0;
+
protected:
LOOLSession(Poco::Net::WebSocket& ws, Kind kind);
virtual ~LOOLSession();
@@ -56,7 +58,6 @@ protected:
void sendBinaryFrame(const char *buffer, int length);
virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0;
- virtual bool getStatus(const char *buffer, int length) = 0;
virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens) = 0;
@@ -105,10 +106,11 @@ public:
static std::map<Poco::Process::PID, Poco::UInt64> _childProcesses;
-protected:
- virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
virtual bool getStatus(const char *buffer, int length);
+ protected:
+ virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
+
virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
void dispatchChild();
@@ -149,10 +151,11 @@ public:
virtual bool handleInput(char *buffer, int length) override;
-protected:
- virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
virtual bool getStatus(const char *buffer, int length);
+ protected:
+ virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
+
virtual void sendTile(const char *buffer, int length, Poco::StringTokenizer& tokens);
bool keyEvent(const char *buffer, int length, Poco::StringTokenizer& tokens);
diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp
index 5b217ab..3b673f0 100644
--- a/loolwsd/TileCache.cpp
+++ b/loolwsd/TileCache.cpp
@@ -21,11 +21,7 @@
#include <Poco/StringTokenizer.h>
#include <Poco/Util/Application.h>
-#include "LOOLProtocol.hpp"
#include "TileCache.hpp"
-#include "Util.hpp"
-
-using namespace LOOLProtocol;
TileCache::TileCache(const std::string& docURL) :
_docURL(docURL)
@@ -122,73 +118,6 @@ void TileCache::saveStatus(const std::string& status)
statusStream.close();
}
-bool TileCache::updateSizeInStatus(const std::string& status, std::string& newStatus)
-{
- std::string dirName = cacheDirName();
-
- Poco::StringTokenizer tokens(status, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- assert(tokens[0] == "documentsizechanged:");
-
- // These messages are constructed directly from the payload in the LO callback. If the payload
- // does not seem to be like we expect, ignore it here. Just let it be passed on to the client.
-
- if (tokens.count() != 3)
- return false;
-
- int newWidth = std::stoi(tokens[1]);
- int newHeight = std::stoi(tokens[2]);
-
- if (newWidth < 0 || newHeight < 0)
- return false;
-
- // Update the size in the cached status, if any
- std::string fileName = dirName + "/status.txt";
- std::fstream statusStream(fileName, std::ios::in);
-
- if (!statusStream.is_open())
- return false;
-
- std::string line;
- std::getline(statusStream, line);
- statusStream.close();
-
- Poco::StringTokenizer oldTokens(line, " ", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM);
-
- std::string type;
- int parts, current, width, height;
- if (oldTokens.count() != 6 ||
- oldTokens[0] != "status:" ||
- !getTokenString(oldTokens[1], "type", type) ||
- !getTokenInteger(oldTokens[2], "parts", parts) ||
- !getTokenInteger(oldTokens[3], "current", current) ||
- !getTokenInteger(oldTokens[4], "width", width) ||
- !getTokenInteger(oldTokens[5], "height", height))
- {
- // Existing status file has wrong syntax. It is useless anyway, delete it.
- Poco::Util::Application::instance().logger().error(Util::logPrefix() + "Cached status '" + fileName + "' is bogus, removing");
- std::remove(fileName.c_str());
-
- return false;
- }
-
- statusStream.open(fileName, std::ios::out);
- if (!statusStream.is_open())
- return false;
-
- line = ("status:"
- " type=" + type +
- " parts=" + std::to_string(parts) +
- " current=" + std::to_string(current) +
- " width=" + std::to_string(newWidth) +
- " height=" + std::to_string(newHeight));
- statusStream << line << std::endl;
- statusStream.close();
-
- newStatus = line;
- return true;
-}
-
std::string TileCache::cacheDirName()
{
Poco::SHA1Engine digestEngine;
diff --git a/loolwsd/TileCache.hpp b/loolwsd/TileCache.hpp
index a6248de..28d8e3a 100644
--- a/loolwsd/TileCache.hpp
+++ b/loolwsd/TileCache.hpp
@@ -28,9 +28,6 @@ public:
// The parameter is a status: message
void saveStatus(const std::string& status);
- // The parameter is a documentsizechanged: message
- bool updateSizeInStatus(const std::string& status, std::string& newStatus);
-
private:
std::string cacheDirName();
std::string cacheFileName(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight);
More information about the Libreoffice-commits
mailing list