GSoC: Documentation #1

This commit is contained in:
Steven Barth 2009-06-13 18:16:34 +00:00
parent 120a7f558e
commit f9263e00c1
5 changed files with 174 additions and 3 deletions

View file

@ -0,0 +1,17 @@
LuCId HTTP/1.1 Server Slave
*** Abstract ***
The LuCId HTTP-Server Slave is an HTTP/1.1 implementation for the LuCId
superserver loosely based on the LuCI HTTP stack. It supports keep-alive,
pipelining, basic authentication, kernel-mode file transfer (sendfile()
through nixio), address and hostname based virtual hosts, custom 404 pages,
E-Tags, conditional headers, directory indexing and partial file transfers.
*** Workflow ***
After receiving an incoming connection from LuCId, the slave parses the request
and prepares the environment for the acion handler. After that the virtual host
will be dispatched and the request will be passed on to the respective handler.
The handler will enforce access restrictions if configured and then returns a
status code a set of response headers, as well as a content resource that will
be sent to the user.

View file

@ -0,0 +1,19 @@
LuCId JSON-RPC Server Slave
*** Abstract ***
The LuCId JSON-RPC server slave implements the JSON-RPC 1.0 and 2.0 protocol
to allow efficient light-weight remote procedure calling.
It provides notification support and several unofficial protocol extensions such
as:
* Close notifications
* Raw TCP switching to transfer BLOBs efficiently
* Client notification
*** Workflow ***
After receiving an incoming connection from LuCId, the slave analyses the
request and passes it to the matching handler. The handler will enforce
access restriction and deserialize the payload data and invokes the assigned
Lua function in a protected way. In case of a success the handler will serialize
the response and send it to the client - otherwise a detailed error message
will be returned.

75
libs/lucid/docs/OVERVIEW Normal file
View file

@ -0,0 +1,75 @@
LuCId Network Superserver in Lua
*** Abstract ***
LuCId is a network superserver written in Lua based on the nixio POSIX library.
It supports IPv4, IPv6, TLS, asynchronous and synchronous IO and can be extended
to handle any kind of IO events on file descriptors. LuCId is also able to
generate RSA private keys and self-signed certificates on demand if the px5g
keymaster library is available. Both nixio and px5g are libraries created
by the LuCI developers.
*** Configuration ***
LuCId uses the UCI Universal Configuration Interface as configuration backend.
There are 4 types of configuration sections and one named section defined:
The main section of type "lucid" defines the basic framework parameters of LuCId
These include:
* pollinterval: Internal polling interval
* threadlimit: Overall maximum number of child processes
* daemonize: Whether to daemonize at startup
* debug: Whether to enable debug output in syslog
The "tcpserver" section type provides the framework for TCP servers:
Parameters:
* entrypoint: Lua module entrypoint (provides a prepare_daemon function)
The "daemon" sections define instances of servers.
Parameters may include:
* slave: Server slave
* publisher: Publishers to be served by this daemon
* enabled: Flag (0/1) whether this daemon should be started
* address: List of ports / addresses to be bound too, if applicable
* encryption: Flag (disabled/enabled) whether to enforce encryption
* tls: Reference to the TLS configuration section to use
The "...Publisher" sections define services to be published through daemons.
Publishers definitions should be daemon and protocol independent whenever
possible. Publishers should also implement access restrictions for certain
network interfaces and for specified UNIX user accounts.
Publishers usually define but are not required to use the following Parameters:
* name: Published Name
* physical: Physical source path
* virtual: Virtual resource path
* domain: Any kind of domain or realm specification
* read: ACL containing entities allowed to read the given resource
* write: -"-
* exec: -"-
The "tls" sections describe TLS security specifications for TCP servers.
Parameters:
* key: Private Key file
* cert: Certificate file
* type: Type of certificate and key files (pem, asn1)
* generate: Flag (0/1) to determine whether LuCId should generate
keys and self-signed certificates if the certificate is not available and
the px5g RSA Keymaster is available
*** Workflow ***
In the preparation phase LuCId loads its configuration using the specification
given above and prepares its servers, daemons and publishers. It also allocates
resources such as binding sockets or preparing encryption credentials.
If everything could be setup correctly LuCId will daemonize - if requested. If
any errors occur in the preparation phase, LuCId will write to the system logger
and exit.
After daemonizing the main process is responsible for keeping a list of
file descriptors that LuCId is polling regularly to handle incoming data events.
Data events are for example new TCP connection attempts which could cause the
superserver to fork a new process and invoke a registered handler.
Whenever a sub-process is about to be generate LuCId checks if given resource
limits are still met.

View file

@ -41,7 +41,7 @@ local UCINAME = UCINAME
local SSTATE = "/tmp/.lucid_store" local SSTATE = "/tmp/.lucid_store"
--- Starts a new LuCId superprocess.
function start() function start()
prepare() prepare()
@ -60,6 +60,7 @@ function start()
run() run()
end end
--- Stops any running LuCId superprocess.
function stop() function stop()
local pid = tonumber(state:get(UCINAME, "main", "pid")) local pid = tonumber(state:get(UCINAME, "main", "pid"))
if pid then if pid then
@ -68,6 +69,7 @@ function stop()
return false return false
end end
--- Prepares the slaves, daemons and publishers, allocate resources.
function prepare() function prepare()
local debug = tonumber((cursor:get(UCINAME, "main", "debug"))) local debug = tonumber((cursor:get(UCINAME, "main", "debug")))
@ -104,6 +106,8 @@ function prepare()
end) end)
end end
--- Run the superprocess if prepared before.
-- This main function of LuCId will wait for events on given file descriptors.
function run() function run()
local pollint = tonumber((cursor:get(UCINAME, "main", "pollinterval"))) local pollint = tonumber((cursor:get(UCINAME, "main", "pollinterval")))
@ -136,11 +140,20 @@ function run()
end end
end end
--- Add a file descriptor for the main loop and associate handler functions.
-- @param polle Table containing: {fd = FILE DESCRIPTOR, events = POLL EVENTS,
-- handler = EVENT HANDLER CALLBACK}
-- @see unregister_pollfd
-- @return boolean status
function register_pollfd(polle) function register_pollfd(polle)
pollt[#pollt+1] = polle pollt[#pollt+1] = polle
return true return true
end end
--- Unregister a file desciptor and associate handler from the main loop.
-- @param polle Poll descriptor
-- @see register_pollfd
-- @return boolean status
function unregister_pollfd(polle) function unregister_pollfd(polle)
for k, v in ipairs(pollt) do for k, v in ipairs(pollt) do
if v == polle then if v == polle then
@ -151,6 +164,8 @@ function unregister_pollfd(polle)
return false return false
end end
--- Close all registered file descriptors from main loop.
-- This is useful for forked child processes.
function close_pollfds() function close_pollfds()
for k, v in ipairs(pollt) do for k, v in ipairs(pollt) do
if v.fd and v.fd.close then if v.fd and v.fd.close then
@ -159,11 +174,19 @@ function close_pollfds()
end end
end end
--- Register a tick function that will be called at each cycle of the main loop.
-- @param cb Callback
-- @see unregister_tick
-- @return boolean status
function register_tick(cb) function register_tick(cb)
tickt[#tickt+1] = cb tickt[#tickt+1] = cb
return true return true
end end
--- Unregister a tick function from the main loop.
-- @param cb Callback
-- @see register_tick
-- @return boolean status
function unregister_tick(cb) function unregister_tick(cb)
for k, v in ipairs(tickt) do for k, v in ipairs(tickt) do
if v == cb then if v == cb then
@ -174,10 +197,14 @@ function unregister_tick(cb)
return false return false
end end
--- Create a new child process from a Lua function and assign a destructor.
-- @param threadcb main function of the new process
-- @param waitcb destructor callback
-- @return process identifier or nil, error code, error message
function create_process(threadcb, waitcb) function create_process(threadcb, waitcb)
local threadlimit = tonumber(cursor:get(UCINAME, "main", "threadlimit")) local threadlimit = tonumber(cursor:get(UCINAME, "main", "threadlimit"))
if threadlimit and tcount >= threadlimit then if threadlimit and tcount >= threadlimit then
nixio.syslog("warning", "Unable to create thread: process limit reached") nixio.syslog("warning", "Cannot create thread: process limit reached")
return nil return nil
end end
local pid, code, err = nixio.fork() local pid, code, err = nixio.fork()
@ -193,6 +220,9 @@ function create_process(threadcb, waitcb)
return pid, code, err return pid, code, err
end end
--- Prepare a daemon from a given configuration table.
-- @param config Configuration data.
-- @return boolean status or nil, error code, error message
function prepare_daemon(config) function prepare_daemon(config)
nixio.syslog("info", "Preparing daemon " .. config[".name"]) nixio.syslog("info", "Preparing daemon " .. config[".name"])
local modname = cursor:get(UCINAME, config.slave) local modname = cursor:get(UCINAME, config.slave)
@ -210,6 +240,9 @@ function prepare_daemon(config)
return module.prepare_daemon(config, _M) return module.prepare_daemon(config, _M)
end end
--- Prepare a slave.
-- @param name slave name
-- @return table containing slave module and configuration or nil, error message
function prepare_slave(name) function prepare_slave(name)
local slave = slaves[name] local slave = slaves[name]
if not slave then if not slave then
@ -228,16 +261,24 @@ function prepare_slave(name)
end end
end end
--- Return a list of available network interfaces on the host.
-- @return table returned by nixio.getifaddrs()
function get_interfaces() function get_interfaces()
return ifaddrs return ifaddrs
end end
--- Revoke process privileges.
-- @param user new user name or uid
-- @param group new group name or gid
-- @return boolean status or nil, error code, error message
function revoke_privileges(user, group) function revoke_privileges(user, group)
if nixio.getuid() == 0 then if nixio.getuid() == 0 then
return nixio.setgid(group) and nixio.setuid(user) return nixio.setgid(group) and nixio.setuid(user)
end end
end end
--- Return a secure UCI cursor.
-- @return UCI cursor
function securestate() function securestate()
local stat = nixio.fs.stat(SSTATE) or {} local stat = nixio.fs.stat(SSTATE) or {}
local uid = nixio.getuid() local uid = nixio.getuid()
@ -253,6 +294,8 @@ function securestate()
return uci.cursor(nil, SSTATE) return uci.cursor(nil, SSTATE)
end end
--- Daemonize the process.
-- @return boolean status or nil, error code, error message
function daemonize() function daemonize()
if nixio.getppid() == 1 then if nixio.getppid() == 1 then
return return

View file

@ -28,7 +28,10 @@ local UCINAME = lucid.UCINAME
local tcpsockets = {} local tcpsockets = {}
--- Prepare a daemon and allocate its resources. (superserver callback)
-- @param config configuration table
-- @param server LuCId basemodule
-- @return binary data
function prepare_daemon(config, server) function prepare_daemon(config, server)
nixio.syslog("info", "Preparing TCP-Daemon " .. config[".name"]) nixio.syslog("info", "Preparing TCP-Daemon " .. config[".name"])
if type(config.address) ~= "table" then if type(config.address) ~= "table" then
@ -104,6 +107,9 @@ function prepare_daemon(config, server)
end end
end end
--- Accept a new TCP connection. (server callback)
-- @param polle Poll descriptor
-- @return handler process id or nil, error code, error message
function accept(polle) function accept(polle)
local socket, host, port = polle.fd:accept() local socket, host, port = polle.fd:accept()
if not socket then if not socket then
@ -133,6 +139,13 @@ function accept(polle)
return unpack(stat) return unpack(stat)
end end
--- Prepare a TCP server socket.
-- @param family protocol family ["inetany", "inet6", "inet"]
-- @param host host
-- @param port port
-- @param opts table of socket options
-- @param backlog socket backlog
-- @return socket, final socket family
function prepare_socket(family, host, port, opts, backlog) function prepare_socket(family, host, port, opts, backlog)
nixio.syslog("info", "Preparing socket for port " .. port) nixio.syslog("info", "Preparing socket for port " .. port)
backlog = backlog or 1024 backlog = backlog or 1024
@ -171,6 +184,10 @@ function prepare_socket(family, host, port, opts, backlog)
return socket, family return socket, family
end end
--- Prepare a TLS server context and load keys and certificates.
-- May invoke px5g to create keys and certificate on demand if available.
-- @param tlskey TLS configuration identifier
-- @return TLS server conext or nil
function prepare_tls(tlskey) function prepare_tls(tlskey)
local tls local tls
if tlskey and cursor:get(UCINAME, tlskey) then if tlskey and cursor:get(UCINAME, tlskey) then