Just a skeleton, actual saving not yet implemented. Also, not sure
the logic when to trigger save is as intended.
Note that no separate timer classes or objects are used. The existing
watpid/sleep loop that wakes up once every two seconds currently is
used. If that loop is re-factored to be less silly, the auto/idle save code
must be implemented differently.
When no child process has died, I don't see the point in calling
waitpid() eleven times in quick succession (with WNOHANG), doing
nothing else, and then sleeping for a bit. Let's call waitpid() just
once, and sleep only if the return value indicates that no child
process has died.
Use same port (9989) for all client connections. This includes
admin panel, static file serving and normal client websocket
connections.
Change-Id: Idcfd7dd8925523c36e884717c41a3b6a827f6ff3
File server serves the admin html file after successfull
authentication, and sets the cookie in client which would be sent
for all subsequent connections by client to connect to admin websocket.
Change-Id: I0ee3bbfca7eefc428020d29612374410556b1e27
Only purpose, at the moment, is to create
Poco::HTTPRequestHandler which would be passed on the serving
handling the static file requests.
Change-Id: I97c3fc0c73da077d3efee919416098b880c9c2ad
... and use SSL for client connections. Also fix our test suite
to use HTTPS now.
Change-Id: Id396a7c2d1830da8d3b0ce446522403363ac17c1
Reviewed-on: https://gerrit.libreoffice.org/23395
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
File server serves the admin html file after successfull
authentication, and sets the cookie in client which would be sent
for all subsequent connections by client to connect to admin websocket.
Change-Id: I0ee3bbfca7eefc428020d29612374410556b1e27
Only purpose, at the moment, is to create
Poco::HTTPRequestHandler which would be passed on the serving
handling the static file requests.
Change-Id: I97c3fc0c73da077d3efee919416098b880c9c2ad
... and use SSL for client connections.
Change-Id: Id396a7c2d1830da8d3b0ce446522403363ac17c1
Reviewed-on: https://gerrit.libreoffice.org/23395
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
To make room for other classes deriving from AuthBase that do not
require any authorization code, such as JWT authentication.
Change-Id: I69a35dd6f775badd7377949df2ca326c910d4021
This is to distinguish the deliberate close of connection, and timeout,
connection drop, or forced close.
When the last session is closed non-deliberately, force a save so that the
edits are not lost.
Ideally, we will have a randomized path for the jails.
Unfortunately, this will make it harder to cleanup
after an ungraceful exit of a child, including recovery
of docs etc.
Having a PID for the jailId makes this issue easier by
implicitly implying the jail path for a given child.
To prevent security leaks, we should at least randomize
the doc directory within the jail, as such:
/chroot/<pid>/user/docs/<rand>/
For now we use jailId=pid=rand.
Change-Id: I948fba0aaef725c9c059780df0a184a86569d898
Reviewed-on: https://gerrit.libreoffice.org/23223
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Renamed DocumentStoreManager to DocumentBroker and
restructured the handshake process.
Currently, at first client connection to a given doc
a DocumentBroker is created to serve as the clearing house
of all client-side activities on the document.
Prime goals is loading and saving of the document, but
also to guarantee race-free management of the doc.
Each doc has a unique DocKey based on the URL (the path,
without queries). This DocKey is used as key into a map
of all DocumentBrokers. The latter is shared among
MasterProcessSession instances.
Change-Id: I569f2d235676e88ddc690147f3cb89faa60388c2
Reviewed-on: https://gerrit.libreoffice.org/23216
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
The current format is more flexible and standard.
/loolwsd/child?sessionId=xxx&jailId=yyy
The sessionId is the client-specific connection ID (which
is originally passed to the child via the Broker.
The jailId is the PID of the child.
Change-Id: I69c88e84114f9678addf795896ca2da15ca1221b
Reviewed-on: https://gerrit.libreoffice.org/23211
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
By default, queries and stores the total memory usage in
AdminModel every 5 seconds, and caches the last 100 such values.
Both cache size and interval can be changed by simple commands
from the clients.
Change-Id: I86cf8228d0129dc8aab0a03856c12dfeb240b169
Well, it was already there.
e7f75a3e56 was though correct
introduced it again. Remove duplicate such call.
Change-Id: Iddacbee53aaec58340db489e7830af75354aee34
It is desirable to have colored logs when running loolwsd
in a terminal, but not redirecting its output to a file.
Outputting to a terminal is now detected and colored logs
are automatically enabled.
To force colored logs in files as well, define
LOOL_LOGCOLOR in the environ. The output color codes
can then be processed using, f.e., `less -r`.
Change-Id: I09fbee4441f210d814ac5ad23dd99d1c33b560b7
Reviewed-on: https://gerrit.libreoffice.org/23080
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
... for which they want to be notified.
Needed to add some missing header files to Storage and Auth class
because of conflict raised when LOOLWSD.hpp is included in
Admin.cpp
Change-Id: Ia1c8ed82f8cd979eaf93267ae5dfa347acf895f4
Further changes/refactoring to make it possible:
* Add broker pid to Admin class
* Move getMemoryUsage for process to Util
* Change variable name to accurately reflect *active* items
_nViews -> _nActiveViews, etc.
Change-Id: I4c9206c49ab829b73ebfe226874bfbbcc8f95342
Reviewed-on: https://gerrit.libreoffice.org/22989
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
Otherwise the process could terminate while admin sessions are still
being served.
Change-Id: Id91d0989e264e8294827e8e2ad8dd2d44b6006ec
Reviewed-on: https://gerrit.libreoffice.org/23021
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
Much simpler.
Also, don't duplicate the code informing that LD_BIND_NOW or
LOK_VIEW_CALLBACK are not set. Not that I understand why we need to
inform about that? If the "normal" thing should be that they are set,
why don't make it so by default then?
I occasionally saw a deadlock when running 'make check' where one
thread holds the ChildProcessSession::Mutex and wants the _mutex for a
Document, while another thread holds that _mutex and wants the
Mutex. In particular, it is the Document::onUnload() that wants the
_mutex. So avoid the deadlock by having Document::onUnload() first
take the ChildProcessSession::Mutex.
The callbacks from documentLoad() are made in the same thread.
Sure, as such it is not a good thing to use recursive mutexes. If we
switch back to non-recursive mutexes, we will have to stop taking the
lock in callbacks from documentLoad(), i.e. make sure we know those
functions aren't used elsewhere, in places where a lock would be
needed. Or something.
If a client session closes just after sending a load message to load a
document, and another session then fairly immediately connects and
sends a load message for the same document, the latter session gets
handled by the same kit process. Also, the same Document object is
apparently used. In that kit process, the first documentLoad() might
easily still be in progress. The handler for the new session still
calls onLoad(), too, and as the first onLoad() had dropped the lock
for the duration of the documentLoad() call, the new onLoad can take
the lock and call documentLoad(), too, while the first documentLoad()
call in the other thread still is in progress. This leads to
interesting problems.
It is loolwsd that spawns loolbroker so we control what arguments it
gets, so no need to give verbose errors if our own code is
inconsistent. That is what assert() is for.
Admin web sessions are added as subscribers to AdminModel. Live
notification fill up the AdminModel, and notifies to
subscribers, if present any. AdminModel can also be queried to
fetch any previous data since the start of the server including
expired documents/views with timestamps for analysis.
There is lot of stuff that can be added in future. This commit
just lays the foundation of appropriate classes.
Change-Id: Ifcf6c2896ef46b33935802e79cd28240fd4f980e
Reviewed-on: https://gerrit.libreoffice.org/22869
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
As a test, add command to fetch documents from AdminModel.
Change-Id: I3cb7097ba7dde049f3b2478fe7b6b6c309da1d92
Reviewed-on: https://gerrit.libreoffice.org/22781
Reviewed-by: Tor Lillqvist <tml@collabora.com>
Tested-by: Tor Lillqvist <tml@collabora.com>
Turns out the callbacks from documentLoad() are in general done on
another thread, not necessarily the same one that did the
documentLoad() call. Not sure why it happened to be the same thread
for me, but oh well. Need to fix the problem described in
3671abf89b in some other way then.
This reverts commit 2fab757462.
The callbacks from documentLoad() are made in the same thread.
Sure, as such it is not a good thing to use recursive mutexes. If we
switch back to non-recursive mutexes, we will have to stop taking the
lock in callbacks from documentLoad(), i.e. make sure we know those
functions aren't used elsewhere, in places where a lock would be
needed. Or something.
... and Admin and AdminModel containing all the required data
that we need to expose to Admin panel.
Admin processor will keep listening to any data on this
notification pipe and update AdminModel accordingly.
Change-Id: I0dd6f07ae60158733c34d17f53a35def70600513
Reviewed-on: https://gerrit.libreoffice.org/22780
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
It does quite a lot of work that can produce very many lines of log,
so it is good to be able to quickly find when that is done when
perusing a log file.
Not needed after all. It was a red herring. The device files work fine
even if not owned by root:root and with mode 664. The actual problem
was that I used a file system mounted with nodev when testing loolwsd.
This reverts commit 509314d559
That is probably what was the intent. As originally written, in case
the function encountered partial writers, and had to do several
write() calls, only the number of bytes written by the last one was
returned.
Luckily the actual return value of writeFIFO() is not used
anywhere. It is just tested for being negative.
Still there is the problem that if at first one or several write()
calls succeed but don't write the whole buffer, and then a write()
fails, the caller has no way to know that the buffer has been
partially written. But that is hopefully highly theoretical and there
is no sane way to handle such a situation anyway.
The getChildStatus() and getSignalStatus() functions returned the
latter, still the returned values were compared against
Poco::Util::Application::EXIT_OK. (Sure, both Poco's
Application::EXIT_SUCCESS and stdlib.h's EXIT_OK are zero, but that
doesn't mean one should mix them up.)
Also add two comments pondering the meaning of the code.
We are not interested in the variable being assigned an incremented
value. Its value is not used any more. We are just interested in the
value of the variable plus one. Using pre-increment gives the wrong
impression.
Sure, this is nit-picking.
So don't give it any then.
Remove the --uid option and related attempts to handle running loolwsd
under sudo, to be able to debug it. Now with loolwsd not having
capabilities, it should work fine to just run it under a debugger
normally. (For the loolbroker and loolkit processes, attaching to an
already started process is the way to debug.)
One has to love arbitrary retry counts and timeouts. Loading the
password-protected.ods in a loolkit process, with correct password
provided, takes 12 seconds on my machine. I think this slowness is
because the NSS code LO uses to do crypto wants to initialize its
crypto goodness in various ways that don't work so well inside a
chroot jail. Presumably it uses some wait with timeout when attempting
to do something which doesn't succeed. For instance it tries to run
netstat -in. (In an interactive LibreOffice the doc loads fairly
instantly.) Oh well.
It does three separate things, and the first two intentionally result
in errors, and the server probably disconnects after errors. Not
sure. This is horrible, horrible.
Having a separate "disconnect" message is a disgrace. There should be
no need for it. WebSocket has a perfectly fine graceful disconnect
mechanism already (CLOSE frames). The code needs to be prepared to
receive a CLOSE frame at any time. The code also needs to be prepared
for the underlying socket being bluntly closed by the other end,
without sending any WebSocket CLOSE frame. The only sane thing is to
handle a "disconnect" message in the same way as those situations
anyway, so why is it needed?
Sort #includes and using statements. Use 'using' consistently for all
Poco:: types. (I am not 100% convinced that using 'using' like done
here in loolwsd was a good idea after all. But at least let's be
consistent now that we do use it.)
No need to pass the value of a variable, initialised much earlier, to
a system call when one can pass the required constant value as
such. Much clearer.
Sorry, could not resist. Obviously not very important.
In retrospect, maybe it would have been better to have as policy to
*not* use any 'using Poco::Foo'. Now there is an inconsistent mix of
writing out the complete type and using a 'using'. Plus copy-pasted
long lists of 'usings'. And of course, one should never have 'using'
in an include file. Oh well.
This is possible by moving all the password handling logic to
Document container class. When a user opens a password protected
document the first time, it saves all possible data such as
password, password type etc. Upon opening the same document
again, password is matched with the cached password saved in the
document container class before allowing the new view access to
this document.
Change-Id: Id1f2b6e06de806564bf865e83fed51b01c9a0fbc
Reviewed-on: https://gerrit.libreoffice.org/22208
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Sometimes there are situations when `connection` map is filled
with dead sessions. We don't want to deal with those dead ones.
Change-Id: I00dda77c39b5adbba69421eace0be0159e02505c
Reviewed-on: https://gerrit.libreoffice.org/22207
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
There are 5 LOK callbacks currently that are triggered on LOKit,
and not on LOKitDocument. These include status indicators, and
document password callbacks during document load. Lets move all
the callbacks called during document load in the Document container
itself, and keep the callbacks called after document load in the
Child session.
Change-Id: I8e43c2baaa12023b34822954dd494780ee6dd7ca
Reviewed-on: https://gerrit.libreoffice.org/22206
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Don't let them hanging around, otherwise we would keep sending
messages to a dead peer (ToClient) indefinitely.
Change-Id: I9d4bb6edee351bd31f1faa30deaa4f37c3c7d031
Reviewed-on: https://gerrit.libreoffice.org/22465
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Our DocumentCallback is smart enough which checks all the
running connections, and send the callback notification to all of
them. Registering the callback only during the first loadDocument
call should be enough.
Change-Id: I82bcb9525814dae14def3bfb6c088337d0d0ea3c
Reviewed-on: https://gerrit.libreoffice.org/22202
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
An abstract Storage abstraction class is added.
There will be a factory to instantiate concrete
implementation for a given backend.
For WebDAV and similar hosted backends, authentication
and authorization will be done by the implementation
with the help of the Auth abstraction.
Change-Id: I38ec5dad4c2c4ce16df30d65826df96751b10e2d
Reviewed-on: https://gerrit.libreoffice.org/22513
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
An abstract class to request an access token, given
an authorization grant. The class should be
specialized for each authentication/authorization
type we support.
Currently it's not enabled in the code as it's
an early stage in developing an general API.
Change-Id: I4f2efd376d575640bd3e17c7257994020b11bbe8
Reviewed-on: https://gerrit.libreoffice.org/22512
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
... and revert back with this parameter in 'tile:' response
messages so that client can identify the response.
This is also required to make client-side tile benchmarking tests
work again.
Change-Id: I307aabf622b17f4dce727d1faf3c83eb566ba905
Create a corresponding symlink inside the chroot.
Now a LOK_PREINIT=1 loolwsd starts up for me successfully. (Note: I
did not say whether it actually works. I don't know yet.)
Sleeps a "kit" process after fork() for the specified number of
seconds to give you time to attach it in the debugger.
Also, if set, have the parent ("broker") process wait indefinitely the
fifo to become writable.
Also clarify the informative message for SLEEPFORDEBUGGER.
globalPreinit() does not run in a chroot as far as I see, so trying to
use loSubPath as an absolute path will not work. Probably what was
meant is loTemplate, then the libraries at least are found.
If neither libsofficeapp.so or libmerged.so exist where we look for
them, say so explicitly.
Log the error message from dlerror(), too.
Log the mesage about not forking in all cases when doing that, not
just if lok_preinit is not found.
Execing is not an alternative to fork(), spawning is.
A load document operation may fail, for example, when user enters
a wrong password or no password. In such cases ToPrisoner sends a
disconnect to child. Child do not need to take any steps in this
case, such as, decrementing the view counter, because nothing was
loaded.
Change-Id: Ib71f871aa1728c6355563362987800dece1679d3
Reviewed-on: https://gerrit.libreoffice.org/22203
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>
Otherwise we have a problem when cached information is different than
the actual one maintained by LOKitDocument, keeping the whole
server setup in an inconsistent state.
For example, when client reloads the browser session quickly
after setting the current part (to say 3) of an opened part document.
If the reload occurs soon enough before the 'setclientpart'
message originated from the client is acknowledged by the server,
then the next reload would get the cached 'status' entry asking
the client to set 'currentpart' to something else leading to the
generation of another 'setclientpart' message. This thing would
go on, and we would run into a loop, as I have for the last few
hours.
Change-Id: Ia6260dfb772f2e3f023572aa060fd7da92b196c8
Reviewed-on: https://gerrit.libreoffice.org/22272
Reviewed-by: Ashod Nakashian <ashnakash@gmail.com>
Tested-by: Ashod Nakashian <ashnakash@gmail.com>