                        The KDE XmlRpc Daemon

                   Kurt Granroth <granroth@kde.org>
                          November 12, 1999

Executive Description
---------------------
This document describes the KDE XmlRpc Daemon (kxmlrpcd).  This daemon
permits a client implemented in nearly  any language (python, perl,
java, etc) on nearly any platform (unix, windows, macos, etc) to
access KDE DCOP clients (servers).  Neither the client nor the server
need any modifications (or any extra knowledge) to take advantage of
this.  Since most KDE applications are or will soon be DCOP client/
servers, this effectively means that all KDE apps can be remotely
manipulated (scripted) by any language on any platform.

Background
==========
XmlRpc is a standard way of implementing remote procedure calls (RPC)
using XML and HTTP.  It's goals are to use "commodity" tools for
everything so that implementation is as simple as possible.  To
accomplish this, it uses XML to mark up all of the method calls (and
parameters) as well as the return values.  It then uses HTTP to
transfer the method call.

The advantage of this approach is that nearly every single decent
language (scripting or otherwise) has free and easy to use XML parsers
and HTTP clients.  This makes implementation relatively easy for most
parts of XmlRpc.  Since it is so easy to implement, there are clients
and servers for many languages with more coming at a pretty constant
rate.

Please check out http://www.xmlrpc.com for more info (including the
spec and a list of clients and servers)

The Problem
-----------
XmlRpc seems to be a wonderful way of doing simple remote access to
KDE applications.  My original plan was to have all KDE apps that
wanted such access to embed an XmlRpc server.  While this would have
worked, it probably wouldn't have had all that many takers... at least
at first.  And after DCOP was introduced, it became obvious that
application authors wouldn't want to implement the remote functions
for both XmlRpc and DCOP.

The Solution
------------
The DCOP library has one huge advantage over XmlRpc.. it is linked to
every single KDE application.  This means that many many apps will
have remote functionality in DCOP if only because it is so incredibly
easy to use.  I decided to exploit this popularity by creating an
XmlRpc to DCOP "gateway".  That is, all incoming XmlRpc requests will
be "translated" to DCOP.. and vice versa

The KDE XmlRpc Daemon
=====================
The result was the KDE XmlRpc Daemon (kxmlrpcd).  It is essentially a
web server running on a random port.  It is both an XmlRpc server and
a DCOP client.

A typical scenerio looks this: 

xmlrpc client                 kxmlrpcd            dcop client
     |<=========================>|<===================>|
              (XmlRpc)                   (DCOP)

The dcop client is registered as 'testDCOP' and has an object name
'test'.

The XmlRpc client sends a methodCall to the daemon at the URL
'http://localhost:<port>/testDCOP' with a methodName of
'test.function' and two strings as params.  The daemon accepts this
request and "translates" it into DCOP by converting the XmlRpc params
into Qt types (QString, in this case) and serializing them into a
QDataStream.  It then will call the dcop client and await a response.
Once the response comes back from the dcop client, it packages it back
up as XmlRpc and returns the result to the xmlrpc client.

Note that the XmlRpc client does not know that it is interacting with
a DCOP client at all.  It thinks that the server is kxmlrpcd.
Likewise, the DCOP client thinks that it is communicating entirely
with another DCOP client called 'kxmlrpcd'.

Authentication
--------------
Originally, the daemon ran on a fixed port (6242) and accepted all
requests.  This has two potentially serious problems with it.
Specifically, the fixed port meant that only *one* person on every
computer could run the daemon.  This is unacceptable for shared
computers.

The more serious problem was one of authentication.  That is, there
was none.  That means that *anybody* on any machine anywhere on the
'net could directly access your DCOP objects as if they were you.
This is a terrible security risk!

The way the daemon gets around these problems is to store a random
port number AND an "authentication token" (seperated by a comma) in
the file $HOME/.kxmlrpcd.  The token is a 16 byte string of random
ASCII characters.  This token needs to be included in every methodCall
as the first string parameter.  If it is NOT the first string
parameter, then the server will reject the request.

This method has the advantage of putting the "real" authentication out
of the realm of the daemon.  This is because it is the client's
responsibility to get the auth token in the first place.  In order for
this to happen, the user would have had to go through some means of
strong authentication already (logging in, mounting a shared drive,
etc).

There are still at least two ways that this level of security could be
circumvented.  The easiest way would probably involve packet sniffing
to just read the auth token as it goes past.  The only way around this
is to involve something like ssh or ssl... neither of which I'm
willing to do as they involve crypto -- a scary topic when you're
working on an international project.

The second way is to just brute force the token.  However, since there
are 79^16 possible combinations, doing so would take effectively
forever even at 1000 trys per second (unlikely)

Ease of Use
-----------
You may be asking "is it really all that easy to use".  The answer is
"yes".  Check out the python and Bourne shell scripts in the 'test'
directory for examples of it.  And yes, you read that right -- you can
use a plain old shell script to remotely access (script) all KDE
applications!

Limitations of This Approach
----------------------------
This approach is great in the sense that neither the client nor the
server need to add any code in order to take advantage of this.
However, this means that there must necessarily be some limitations on
it's use.

o It is not possible to use Qt types directly

  The only types that are usable are those that have a direct mapping
  between the XmlRpc type and the Qt type.  Those are:

  ----------------------------------------
  XmlRpc        Qt/C++
  ------    =>  ------
  <int>         int
  <boolean>     bool
  <string>      QString (See Unicode)
  <double>      double
  <dateTime>    QDateTime
  <base64>      QByteArray
  <struct>      QMap (See limited types)
  <array>       QArray (See limited types)

  ----------------------------------------

  Note that types such as QPixmap, QList, etc are not allowed

o Unicode support is iffy

  I don't know how well Unicode is supported in XML.  As a percaution,
  I am using QStrings everywhere... but I really don't know if it's
  worth it.

o <struct> and <array> is severly restricted  

  As described in the XmlRpc spec, structs and arrays can have any
  number of different types.. including recursive structs and arrays.
  Unfortunately, there is no way to easily map such structures into
  C++ types as C++ lacks a simple way to create dynamic types on the
  fly.

  It is possible to use <struct> and <array> IF the following
  two restrictions are followed:

  1) Each <struct> or <array> can contain exactly ONE typeo
  and
  2) <struct> and <array> may NOT contain other structs or arrays.
     They may contain only the other simple types

Current Status
==============
This section will hopefully be kept up to date as to the current
status of this daemon.

Current Status as of Oct 25, 1999
---------------------------------
Types:
<int>      -  Fully implemented
<double>   -  Fully implemented
<string>   -  Fully implemented
<boolean>  -  Fully implemented
<base64>   -  Fully implemented
<dateTime> -  Fully implemented (YYYYMMDDTHH:MM:SS, at least)
<struct>   -  Fully implemented / partially tested
<array>    -  Fully implemented / partially tested

Bugs/Missing Features:
o There is a memory leak in kxmlrpcserver.. but I can't find it :-( 
  UPDATE: FOUND IT!  It's a leak in QDomDocument
o The server 'shutdown()' function doesn't quite work right
o Each incoming request takes a separate connection... it should use
  'keepalive' if possible
o Need either a client library OR a way to translate DCOP requests
  (not just responses) into XmlRpc
o This document isn't nearly complete
