libreoffice-online/loolwsd
Pranav Kant 28cf20b091 bccu#1640: Add elapsed time field to admin console
Time increment is handled on client-side, server only sends the
elapsed time during first page-load.

Change-Id: I73e98fd95ca9f391b625a8dcfc7e3490878c6a40
2016-04-01 13:33:45 +05:30
..
bundled/include/LibreOfficeKit Update from LO master 2016-03-04 12:09:14 +02:00
debian We need Poco 1.7.1 now after fb9c9a9ec7 2016-03-21 16:28:33 +02:00
etc loolwsd: Install the certificates during the build. 2016-03-29 13:29:07 +02:00
test loolwsd: new unittests 2016-03-30 02:06:32 +00:00
.gitignore
Admin.cpp loolwsd: Temporarily use hard-coded path to key file 2016-03-31 00:56:57 +05:30
Admin.hpp loolwsd: fix -Werror,-Wunused-private-field 2016-03-22 08:08:44 +01:00
AdminModel.cpp bccu#1640: Add elapsed time field to admin console 2016-04-01 13:33:45 +05:30
AdminModel.hpp bccu#1640: Add elapsed time field to admin console 2016-04-01 13:33:45 +05:30
Auth.cpp loolwsd: Verify JWT token's expiry time 2016-03-31 17:25:29 +05:30
Auth.hpp loolwsd: Split Storage, Auth classes into header/impl files 2016-03-31 12:57:44 +05:30
AUTHORS Anybody interested can check git log 2016-03-01 13:11:00 +02:00
Capabilities.hpp Use std:: consistently for cstdlib functions 2016-03-02 08:47:13 +02:00
ChangeLog
ChildProcessSession.cpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
ChildProcessSession.hpp loolwsd: Move Admin class to separate header 2016-03-03 18:26:55 +00:00
Common.hpp Avoid defining constant strings in multiple places 2016-03-28 14:17:30 +03:00
configure.ac loolwsd: put config file and cert/key files to /etc 2016-03-24 10:37:17 +01:00
Connect.cpp Use SSL here, too 2016-03-22 20:06:44 +02:00
COPYING
discovery.xml loolwsd: update discovery.xml 2016-03-17 19:48:34 -04:00
DocumentBroker.cpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
DocumentBroker.hpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
FileServer.hpp loolwsd: Temporarily use hard-coded path to key file 2016-03-31 00:56:57 +05:30
INSTALL
IoUtil.cpp Improve logging 2016-03-31 11:01:52 +03:00
IoUtil.hpp loolwsd: pipe plumbing cleanup 2016-03-30 02:02:53 +00:00
LoadTest.cpp Use std:: consistently for cstdlib functions 2016-03-02 08:47:13 +02:00
LoadTest.hpp
LOKitClient.cpp loolwsd: LOK_CALLBACK_PARTS_COUNT_CHANGED was removed from the API. 2016-03-03 11:13:34 +01:00
LOKitHelper.hpp Factor out function to get the symbolic name for a LibreOfficeKitCallbackType 2016-03-04 11:49:46 +02:00
LOOLBroker.cpp loolwsd: improved child spawning and management 2016-03-30 02:05:57 +00:00
LOOLKit.cpp loolwsd: Use filename in admin console 2016-03-31 22:47:26 +05:30
loolmap.c loolwsd: -Werror,-Wunused-variable 2016-01-14 12:40:59 +01:00
LOOLProtocol.cpp loolwsd: logging improvements 2016-03-30 02:03:25 +00:00
LOOLProtocol.hpp loolwsd: cleanup of the command parser 2016-03-29 02:47:56 +00:00
LOOLSession.cpp loolwsd: moved IO utilities into IoUtil file 2016-03-29 14:09:04 +00:00
LOOLSession.hpp The jailed processes are not "loolwsd" in any sense any more 2016-03-20 21:52:27 +02:00
loolstat
loolwsd-systemplate-setup Don't pretend this will work on anything except Linux 2016-02-29 14:25:12 +02:00
LOOLWSD.cpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
LOOLWSD.hpp Avoid defining constant strings in multiple places 2016-03-28 14:17:30 +03:00
loolwsd.service loolwsd: add --fileserverroot=/srv/www/htdocs/ to loolwsd.service 2016-03-25 13:08:42 +01:00
loolwsd.spec.in loolwsd: poco soname in loolwsd.spec 2016-03-23 20:20:05 +01:00
loolwsd.xml loolwsd: Add CA path during SSL initialize 2016-03-25 13:01:01 +05:30
Makefile.am loolwsd: Separate AdminModel header and implementation 2016-03-31 13:00:30 +05:30
MasterProcessSession.cpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
MasterProcessSession.hpp bccu#1621: Introduce an edit lock 2016-03-31 19:24:14 +05:30
MessageQueue.cpp MessageQueue: moving a local object in a return statement prevents copy elision 2016-03-29 13:36:30 +02:00
MessageQueue.hpp loolwsd: queue payload changed to vector<char> 2016-03-29 02:47:27 +00:00
NEWS
Png.hpp
PROBLEMS The /dev/random and urandom problem was a red herring 2016-03-15 22:24:58 +02:00
protocol.txt loolwsd, loleaflet: Rename 'connectionclose' to 'disconnect'. 2016-03-15 10:32:28 +01:00
QueueHandler.hpp loolwsd: message handling cleanups 2016-03-29 02:48:28 +00:00
README poco 1.7.2 debian packages 2016-03-23 14:23:41 +01:00
README.vars Clarify semantics of LOK_FORK 2016-03-29 14:33:53 +03:00
Rectangle.hpp loolwsd: doxygenize class comments 2016-01-28 19:16:32 +01:00
reference.txt
Storage.cpp loolwsd: Split Storage, Auth classes into header/impl files 2016-03-31 12:57:44 +05:30
Storage.hpp loolwsd: Split Storage, Auth classes into header/impl files 2016-03-31 12:57:44 +05:30
sysconfig.loolwsd loolwsd: unused LOOLWSD_NUMPRESPAWNS environment variable 2016-03-29 09:36:10 +02:00
TileCache.cpp loolwsd: logging improvements 2016-03-30 02:03:25 +00:00
TileCache.hpp loolwsd: Storage gets last modified time and simplified TileCache construction 2016-03-26 17:10:25 +00:00
TODO
Util.cpp Improve logging 2016-03-31 11:01:52 +03:00
Util.hpp Improve logging 2016-03-31 11:01:52 +03:00

LibreOffice On-Line WebSocket server
====================================

Dependencies
------------

LibreOffice On-Line WebSocket server has the following dependencies:

* libpng
* Poco library: http://pocoproject.org/index.html.
* libcap-progs

Poco can be built with ./configure --prefix=/opt/poco && make install, but
distro packages exist too.

On openSUSE, you can use:

    zypper ar http://download.opensuse.org/repositories/devel:/libraries:/c_c++/openSUSE_13.2/devel:libraries:c_c++.repo
    zypper in poco-devel libcap-progs

On Debian 8 (Linux x86_64) you can use in /etc/apt/sources.list:

    deb https://www.collaboraoffice.com/apt-poco/ /

Building
--------

loolwsd uses autoconf/automake, so build using the usual:

    MASTER=/path/to/built/core.git # configure for your system

    autoreconf
    automake --add-missing
    ./configure --enable-silent-rules --with-lokit-path=${MASTER}/include
    make

where ${MASTER} is the location of the LibreOffice source tree.

Run 'make check' after each commit. Requires loolwsd to be running.

Note that the loolwsd program needs the CAP_SYS_CHROOT capability,
thus you will be asked the root password when running make as it
invokes sudo to run /sbin/setcap.

If you have self-built Poco, add the following to ./configure:

    --with-poco-includes=<POCOINST>/include --with-poco-libs=<POCOINST>/lib

where <POCOINST> means the Poco installation location.

If you have the Poco debugging libraries (eg. you have a self-built
Poco), you can add --enable-debug to the configure options for
additional debugging.

For Windows, a proper VS2013 project is needed.

There is still unconditional debugging output etc. This is a work in
progress.

Running
-------

First create the directory used for caching tiles. It is set as
"${localstatedir}/cache/${PACKAGE}" in the configure.ac, so if you did
not pass any switch to the configure script that affects
"localstatedir, it will be /usr/local/var/cache/loolwsd . If you did
pass such a switch, like --prefix, check config.h for the exact value.

If you're using the defaults you'll need to:

sudo mkdir -p /usr/local/var/cache/loolwsd
sudo chown `whoami` /usr/local/var/cache/loolwsd

Now you need to set up a minimal chroot system, and directory for the jails:

    SYSTEMPLATE=`pwd`/systemplate  # or tweak for your system
    ROOTFORJAILS=`pwd`/jails       # or tweak for your system

    rm -Rf ${SYSTEMPLATE} # clean
    ./loolwsd-systemplate-setup ${SYSTEMPLATE} ${MASTER}/instdir # build template
    mkdir -p ${ROOTFORJAILS} # create location for transient jails.

To run loolwsd the way it is supposed to eventually be run "for real", you can
now do:

    ./loolwsd --systemplate=${SYSTEMPLATE} --lotemplate=${MASTER}/instdir --childroot=${ROOTFORJAILS}

and connect loleaflet to that (see loleaflet/README for more info).

Again, ${MASTER} is location of the LibreOffice source tree with a built
LibreOffice.  This is work in progress, and consequently needs the latest
LibreOffice master.

The ${SYSTEMPLATE} is a directory tree set up using the
loolwsd-systemplate-setup script here. (It should not exist before
running the script.) It will contain the runtime environment needed by
the LibreOffice dynamic libraries used through LibreOfficeKit.
Improvements to that script are very likely needed on various distros.

The ${ROOTFORJAILS} directory above is a presumably initially empty
directory under which loolwsd will create chroot jails for editing
each specific document.

As loolwsd uses hardlinks to "copy" the contents of both
${SYSTEMPLATE} and the ${MASTER}/instdir directories into each chroot
jail, ${SYSTEMPLATE} and ${MASTER}/instdir need to be on the same file
system as ${ROOTFORJAILS}.

Leaflet files are served itself by loolwsd internal file server. You can specify the
root of this fileserver using the --fileserverroot flag in loolwsd commandline.
By default, if you do not specify this flag, the parent directory of loolwsd/
is assumed to be the fileserverroot. So, for development purposes, you can access
the leaflet files (using /loleaflet/), but it is advised to explicitly set the
fileserverroot to prevent any unwanted files from reading, especially when lool
is deployed for normal public usage on servers.

Please note that it is necessary that all the leaflet files that are meant to be
served is under a directory named 'loleaflet'. Since, the loleaflet files, in
lool git repo, are itself in a directory named 'loleaflet', this would work out of
the box for development purposes.

loolwsd only runs on HTTPS which means you would have to set up your own private
key and certificate (in PEM format only). Currently, loolwsd assumes files with
name cert.pem, and key.pem to be certificate and private key respectively.
Dummy self-signed cert.pem and key.pem are already included, but it is better
to replace those with your own files.

If you plan to hack on loolwsd, you probably want to familiarize
yourself with loolwsd's --test and --numprespawns switches, and the
'connect' test program.

For interactive testing, you can use the loolwsd --test switch, or you
can use the 'connect' program. Both accept "commands" from the
protocol on standard input. You can either used them tuly
interactively, or edit input lines into a file, or use shell
scripting, etc. For instance:

    (echo load /some/where/foo.odt; echo tile part=0 width=500 height=500 tileposx=0 tileposy=0 tilewidth=10000 tileheight=10000; sleep 10) |
    ./loolwsd --test --systemplate=/home/tml/lo/master/lool-sys-template --lotemplate=/home/tml/lo/master/instdir --childroot=/home/tml/lo/master/lool-child-root

Admin Panel
-----------

You can access the admin panel by directly acessing the admin.html file from loleaflet directory.
See loleaflet/README for more details.

Debugging
---------

When debugging, you want to add --numprespawns=1 to the loolwsd parameters to
limit the amount of concurrently running processes.

When the crash happens too early, you also want to

    export SLEEPFORDEBUGGER=<number of seconds>

so that you have time to attach to the process.

Then run loolwsd, and attach your debugger to the process you are
interested in. Note that as the loolwsd executable file has
capabilities set, you need to run the debugger with super-user
privilege.

Also, note that as the child processes run in a chroot environment,
they see the LibreOffice shared libraries as being in a directory tree
/lo , but your debugger does not. So in order to be able to
effectively debug the LibreOffice code as used through LibreOfficeKit
by a child loolwsd process, you need to symlink the "lo" subdirectory
of a running child loolwsd process's chroot jail as /lo. Something like:

sudo ln -s ~/libreoffice/master/lool-child-roots/1046829984599121011/lo /lo

Use the ps command to find out exactly the path to use.

Set LOOL_DEBUG=1 to trap SIGSEGV and SEGBUS and prompt for debugger.

Protocol description
--------------------

See protocol.txt for a description of the protocol to be used over the
websocket.

Architecture
------------

There are three processes: LoolWSD, LoolBroker, and LoolKit.

WSD is the top-level server and is intended to run as a service.
It is responsible for spawning Broker and listening on public
port for Client connections.

The Broker is only responsible for spawning (or forking) Kit
instances. There is only one Broker per WSD instance and
there is one Kit instance per document.

WSD listens on a public port and using internal pipes requests
the Broker to fire a child (Kit) instance to host documents.
The Broker then has to find an existing Kit that hosts that
document, based on the public URI as unique key, and forward
the request to this existing Kit, which then loads a new
view to the document.

There is an additional pipe that kit processes and broker have
write access to. This pipe is 'notify' pipe. All the important
changes are notified on this pipe. The pipe is read by the admin
manager continously and it keeps updating the AdminModel object.
AdminModel object has subscribers which corresponds to admin
panel sessions. Subscriber can subscribe to specific commands
to get live notifications about, and to update the UI accordingly.

Whether a document is loaded for the first time, or this is
a new view on an existing one, the Kit connects via a socket
to WSD on an internal port. WSD acts as a bridge between
the Client and Kit by tunnelling the traffic between the two
sockets (that which is between the Client and WSD and the one
between WSD and Kit).

File System
-----------

WSD is given childroot argument on the command line. This is
the root directory of jailed FS. This path can be anywhere, but
here we'll designate it as:

/childroot

Before spawning a Broker instance, WSD needs to generate a random
Jail-ID to use as the jail directory name. This JailID is then
passed to Broker as argument jailid.

Note: for security reasons, this directory name is randomly generated
and should not be given out to the Client. Since there is only one
Broker per WSD instance, there is also one JailID between them.

The Broker creates a chroot in this directory (the jail directory):

/childroot/jailid/

Broker copies the LO instdir (essentially installs LO in the chroot),
then copies the Kit binary into the jail directory upon startup.
Once done, it chroot-s and drops caps.

Broker then waits on a read pipe to which WSD writes when a new
request from a Client is received. Broker is responsible for spawning
(or forking) Kit instances. For our purposes, it doesn't matter
whether Kit is spawned or forked.

Every document is hosted by a Kit instance. Each document is stored
in a dedicated directory within the jail directory. The document
root within the jail is /user/docs. The absolute path on the system
(which isn't accessible to the Kit process as it's jailed) is:

/childroot/jailid/user/docs

Within this path, each document gets its own sub-directory based on
another random Child-ID (which could be the Process ID of the Kit).
This ChildId will be given out to Clients to facilitate the insertion
and downloading of documents. (Although strictly speaking the Client
can use the main document URI as key, this is the current design.)

/childroot/jailid/user/docs/childid


A request from a Client to load a document will trigger the following
chain of events.

- WSD public socket will receive the connection request followed
  by a "load" command.
- WSD creates MasterProcessSession (ToClient) to handle the client traffic.
- MasterProcessSession requests Broker to find or spawn Kit for
  the given URI.
- Broker sends Kit request to host URI via pipe.
- Kit connects to WSD on an internal port.
- WSD creates another MasterProcessSession (ToPrisoner) to service Kit.
- MasterProcessSession (ToClient) is linked to the ToPrisoner instance,
  copies the document into jail (first load only) and sends
  (via ToPrisoner) the load request to Kit.
- Kit loads the document and sets up callbacks with LOKit.
- MasterProcessSession (ToClient) and MasterProcessSession (ToPrisoner)
  tunnel the traffic between Client and Kit both ways.


Coding style
------------

There is not really any serious rationale why the code ended up being
written in the style it is... but unless you plan to change some style
detail completely and consistenly all over, please keep to the style
of the existing code when editing.

The style is roughly as follows, in rough order of importance:

- As in LO, no hard TABs in source files. Only spaces. Indentation
  step is four columns.

- As in LO, the braces { and } of the block of if, switch, and while
  statements go on separate lines.

- Following Poco conventions, non-static member variables are prefixed
  with an underscore. Static members have a CamelCase name.

- Do use C++11. I admit in some places (out of laziness or ignorance)
  I use Poco API even if there probably is an equivalent std::
  API. (Like for threads.) Feel free to change those, if the std:: API
  is not much more verbose or ugly, and you are sure it is equivalent.

- Always prefer the C++ wrapped version of a C library
  API. I.e. include <cstring> instead of <string.h>, use std::memcpy()
  instead of memcpy(), etc.

- Use std:: prefix for all std API, i.e. don't ever do "using
  std;". But it's OK to use "using Poco::Foo;" all over. Maybe that is
  not a good idea? But please no "using" in headers.

- Member functions use camelCaseWithInitialLowerCase. I don't like
  CamelCaseWithInitialUpperCase.

- [ No kind of Hungarian prefixes. ] This rule seems to have been
  totally ignored lately. So now the codebase is inconsistent in
  naming conventions. Oh well.