[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
4.1 Introduction to servers Protocol servers in Serveez 4.2 Writing servers How to write Internet protocol servers 4.3 Some words about server configuration How do I configure an existing server ? 4.4 Existing servers Which kind of servers do we have already ?
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Serveez is a kind of server server. It allows different protocol servers to listen on various TCP/UDP ports, on ICMP sockets and on named pipes. Servers are instantiated with a certain configuration. It is possible to run multiple different servers on the same port.
This chapter covers all questions about how to write your own Internet protocol server with this package. Most of the common tasks of such a server have got a generic solution (default routines) which could be "overridden" by your own routines. There are some examples within this package. They are showing the possibilities with this package and how to implement servers.
The `foo' server does not do anything at all and is of no actual use but could be a basis for a new protocol server. We are now going to describe how this specific server works. Eventually the reader might get an impression of what is going on.
For better understanding the text below we will use the following terminology:
svz_servertype_t
structure which contains
server specific members like its name, different callbacks, a single default
configuration and a list of configuration items which determines what can be
configured.
svz_portcfg_t
structure. Depending on a shared flag it contains different type of
information specifying a transport endpoint. See section 2.5.1 Define ports, for more
on this topic. It also can be a special configuration item within a server
configuration. This is necessary if a server needs for some reason a remote
transport endpoint. A server instance does not usually need to know about
the port configuration it is bound to.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Serveez is meant to be a server framework. That is why it supports various ways to implement Internet servers. First of all there are some servers already included in the main serveez package. (See section 4.4 Existing servers.) These are called `Builtin servers'. Another possibility to add a new server are `Embedded servers' which are shared libraries (or DLL's) containing the server implementation. These can be dynamically loaded by Serveez at runtime. This kind of server is also called `Server modules'. A third possibility are the `Guile servers' which allow even unexperienced schemers to write an Internet server.
This section describes each of the above possibilities in detail.
4.2.1 Embedded servers How to write dynamic server modules 4.2.2 Guile servers Servers using Serveez's guile interface 4.2.3 Builtin servers Servers located in the main project
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The core library of Serveez can be used to write standalone server modules. Serveez defines a certain interface for shared libraries which contain such server modules. If Serveez detects an unknown server type (server type which is not builtin) in its configuration file it tries to load a shared library containing this server type during startup.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In order to implement a server module you need an existing installation of Serveez. This can be achieved issuing the following commands:
$ ./configure --enable-shared --prefix=/usr/local $ make $ make install |
After successful installation you are able to compile and link against the Serveez core API. The headers should be available in `/usr/local/include' and the library itself (`libserveez.so' or `libserveez.dll') is located in `/usr/local/lib' if you passed the configure script `--prefix=/usr/local'.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The interface mentioned in the introduction is defined via the extern
declaration of the server type in the shared library of the server module.
Imagine you want to implement a server type called `foo'. This requires
the external symbol foo_server_definition
in the shared library.
You can achieve this inserting the following lines into your header file:
/* Either Unices. */ extern svz_servertype_t foo_server_definition; /* Or Windows. */ __declspec (dllexport) extern svz_servertype_t foo_server_definition; |
The data symbol foo_server_definition
must be statically filled with
the proper content (See section 4.2.3 Builtin servers.)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section describes the Guile interface to Serveez which provides the ability to write servers with Guile. Of course, you could do this without any help from Serveez, but it makes the task a lot easier. This interface reduces the Guile implementation of an Internet server to a simple data processor.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Serveez extends Guile by various new data types which represent internal data structures of Serveez's core API.
#<svz-servertype>
represents a server type.
#<svz-server>
represents a server (an instance of a server type).
#<svz-socket>
represents a socket structure.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The new binary data type (#<svz-binary>
) provides access to any
kind of unstructured data. It manages the data exchange between Guile
and Serveez. There are some conversion functions for strings and lists
which help to process this binary data in a more complex (guile'ish) way.
#t
if the given cell binary is
an instance of the binary smob type.
#f
if the needle could
not be found and a positive number indicates the position of the first
occurrence of needle in the binary smob binary.
string->binary
.
long
value of the binary smob binary at the
array index index.
long
value of the binary smob binary at the array
index index to the given value value. The procedure returns
the previous (overridden) value.
int
value of the binary smob binary at the
array index index.
int
value of the binary smob binary at the array
index index to the given value value. The procedure returns
the previous (overridden) value.
short
value of the binary smob binary at the
array index index.
short
value of the binary smob binary at the array
index index to the given value value. The procedure returns
the previous (overridden) value.
char
value of the binary smob binary at the
array index index.
char
value of the binary smob binary at the array
index index to the given value value. The procedure returns
the previous (overridden) value.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In order to set up a new server type, you use the procedure
(define-servertype!)
. This procedure takes one argument which
must be an associative list specifying the server type in detail.
There are optional and mandatory elements you can set up in this alist.
The following example shows the overall syntax of this procedure:
(define-servertype! '( ;; Mandatory: server type prefix for later use in (define-server!) (prefix . "foo") ;; Mandatory: server type description (description . "guile foo server") ;; Mandatory for TCP and PIPE servers: protocol detection (detect-proto . foo-detect-proto) ;; Optional: global server type initialisation (global-init . foo-global-init) ;; Optional: server instance initialisation (init . foo-init) ;; Optional: server instance finalisation (finalize . foo-finalize) ;; Optional: global server type finalisation (global-finalize . foo-global-finalize) ;; Mandatory for TCP and PIPE servers: socket connection (connect-socket . foo-connect-socket) ;; Optional: server instance info (info-server . foo-info-server) ;; Optional: client info (info-client . foo-info-client) ;; Optional: server instance reset callback (reset . foo-reset) ;; Optional: server instance notifier (notify . foo-notify) ;; Mandatory for UDP and ICMP servers: packet handler (handle-request . foo-handle-request) ;; Mandatory: server type configuration (may be an empty list) (configuration . ( ;; The server configuration is an alist (associative list) again. ;; Each item consists of an item name and a list describing the ;; item itself. ;; Syntax: (key . (type defaultable default)) (foo-integer . (integer #t 0)) (foo-integer-array . (intarray #t (1 2 3 4 5))) (foo-string . (string #t "default-foo-string")) (foo-string-array . (strarray #t ("guile" "foo" "server"))) (foo-hash . (hash #t (("foo" . "bar")))) (foo-port . (portcfg #t foo-port)) (foo-boolean . (boolean #t #t)) )))) |
#t
on
success.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following subset of procedures may be used to implement a Guile
server. They should be used within the callbacks defined in the
(define-servertype!)
procedure. Each of these callbacks gets
passed the appropriate arguments needed to stuff into the following
procedures. Please have a look at the example Guile servers for the
details.
#t
if the given cell sock is an instance of a valid
#<svz-socket>
, otherwise #f
.
check-request
member of the socket structure sock
to the Guile procedure proc. Returns the previously handler if
there is any.
check-oob-request
callback
of the given socket structure sock. The previous callback is
replaced by the proc procedure and will be returned if there was
set any before. The callback is run whenever urgent data (out-of-band)
has been detected on the socket.
#<svz-socket>
in sock and an
exact number or single character in oob. The byte in oob
is sent as urgent (out-of-band) data through the underlying TCP stream.
The procedure returns #t
on successful completion and otherwise
(either it failed to send the byte or the passed socket is not a TCP
socket) #f
.
handle-request
member of the socket structure sock
to the Guile procedure proc. The procedure returns the previously
set handler if there is any.
check-request
callback of the given socket
structure sock to a predefined routine which runs the
handle-request
callback of the same socket when it detected a
complete packet specified by boundary. For instance you
can setup Serveez to pass your handle-request
procedure text lines
by calling (svz:sock:boundary sock "\n")
.
#t
on success and
#f
on failure.
(svz:sock:print)
.
#f
if Nagle is active, #t
otherwise). By default this
flag is switched off. This socket option is useful when dealing with small
packet transfer in order to disable unnecessary delays.
#<svz-socket>
. If the user omits
the optional length argument, all of the data in the receive buffer
gets dequeued. Returns the number of bytes actually shuffled away.
PROTO_ICMP
the port argument is
ignored. Valid identifiers for proto are PROTO_TCP
,
PROTO_UDP
and PROTO_ICMP
. The host argument must be
either a string in dotted decimal form, a valid hostname or an exact number
in host byte order. When giving a hostname this operation might be
blocking. The port argument must be an exact number in the range from
0 to 65535, also in host byte order. Returns a valid #<svz-socket>
or #f
on failure.
disconnected-socket
member of the socket structure
sock to the Guile procedure proc. The given callback
runs whenever the socket is lost for some external reason. The procedure
returns the previously set handler if there is one.
kicked-socket
callback of the given socket structure
sock to the Guile procedure proc and returns any previously
set procedure. This callback gets called whenever the socket gets
closed by Serveez intentionally.
trigger
callback of the socket structure sock to
the Guile procedure proc and returns any previously set procedure.
The callback is run when the trigger-condition
callback returned
#t
.
trigger-condition
callback for the socket
structure sock to the Guile procedure proc. It returns the
previously set procedure if available. The callback is run once every
server loop indicating whether the trigger
callback should be
run or not.
idle
callback of the socket structure
sock to the Guile procedure proc. It returns any previously
set procedure. The callback is run by the periodic task scheduler when the
idle-counter
of the socket structure drops to zero. If this counter
is not zero it gets decremented once a second. The idle
callback can reset idle-counter
to some value and thus can
re-schedule itself for a later task.
idle-counter
value. If the optional argument counter is
given, the function sets the idle-counter
. Please have a look at the
(svz:sock:idle)
procedure for the exact meaning of this value.
#<svz-socket>
object or an empty list.
#<svz-socket>
or an empty list.
#<svz-server>
object associated with the
given argument sock. The optional argument server can be used
to redefine this association and must be a valid #<svz-server>
object. For a usual socket callback like connect-socket
or
handle-request
, the association is already in place. But for sockets
created by (svz:sock:connect)
, you can use it in order to make the
returned socket object part of a server.
(host . port)
with both entries in network byte order. If you pass
the optional argument address, you can set the local address of
the socket sock.
(host . port)
with both entries in network byte order. If you pass
the optional argument address, you can set the remote address of
the socket sock.
#<svz-socket>
's identification number and the cdr the
version number. The procedure returns either the identified
#<svz-socket>
or #f
if the given combination is not
valid anymore.
#<svz-socket>
sock which can be passed to
(svz:sock:find)
. This may be necessary when you are passing
a #<svz-socket>
through coserver callback arguments in order to
verify that the passed #<svz-socket>
is still valid when the
coserver callback runs.
PROTO_TCP
, PROTO_UDP
, PROTO_ICMP
,
PROTO_RAW
or PROTO_PIPE
constants indicating the type of
the socket structure sock. If there is no protocol information
available the procedure returns #f
.
(svz:htons)
function converts the 16 bit short integer
hostshort from host byte order to network byte order.
(svz:ntohs)
function converts the 16 bit short integer
netshort from network byte order to host byte order.
(svz:htonl)
function converts the 32 bit long integer
hostlong from host byte order to network byte order.
(svz:ntohl)
function converts the 32 bit long integer
netlong from network byte order to host byte order.
(svz:inet-aton)
function returns #f
if the address is
invalid.
(svz:inet-ntoa)
function converts the Internet host address
address given in network byte order to a string in standard
numbers-and-dots notation.
#t
if the given cell server is an instance of a valid
#<svz-server>
, otherwise #f
.
#<svz-socket>
smobs to which the
given server instance server is currently bound, or an empty list
if there is no such binding yet.
#<svz-socket>
client smobs associated with
the given server instance server in arbitrary order, or an
empty list if there is no such client.
(define-servertype!)
) then it returns
an empty list.
#<svz-server>
or a
#<svz-socket>
. Returns the previously associated object or an
empty list if there was no such association. This procedure is useful
for server instance state savings.
(svz:server:state-set!)
previously. Otherwise
the return value is an empty list. The given server argument must be
either a valid #<svz-server>
object or a #<svz-socket>
.
#t
if the given string name corresponds with a
registered port configuration, otherwise the procedure returns
#f
.
#t
if so.
#t
if so.
Otherwise it returns #f
.
#t
exception handling is enabled and if set to #f
exception handling is disabled. The procedure always returns the
current value of this behaviour.
(quit)
.
(primitive-load)
in serveez configuration files. It tries to locate the given filename
file in the paths returned by (serveez-loadpath)
. If
file cannot be loaded the procedure returns #f
.
(getrpc)
procedure
will take either a rpc service name or number as its first argument;
if given no arguments, it behaves like (getrpcent)
.
(setrpc)
procedure opens and rewinds the file `/etc/rpc'.
If the stayopen flag is non-zero, the net data base will not be
closed after each call to (getrpc)
. If stayopen is omitted,
this is equivalent to (endrpcent)
. Otherwise it is equivalent to
(setrpcent stayopen)
.
IPPROTO_UDP
or IPPROTO_TCP
.
If the user omits protocol and port, the procedure destroys
all mapping between the triple [prognum,versnum,*] and ports
on the machine's portmap service.
(callback addr arg)
. The addr
argument passed to the callback is a string representing the appropriate
IP address for the given hostname host. If you omit the optional
argument arg it is run as (callback addr)
only. The arg
argument may be necessary if you need to have the callback procedure
in a certain context.
(callback host arg)
where host is the hostname of the
requested IP address addr. The last argument arg is
optional.
#<svz-socket>
sock into the
internal ident coserver queue. When the coserver responds, it runs the
Guile procedure callback as (callback user arg)
where
user is the corresponding username for the client connection
sock. The arg argument is optional.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The Guile interface of Serveez is completely callback driven.
Callbacks can be set up in the associative list passed to
(define-servertype!)
, or by using the predefined procedures
described in the previous section. Each of the callbacks is passed
certain arguments and is meant to return specific values to indicate
success or failure. This section describes each of these callbacks.
(global-init #<svz-servertype>)
(define-servertype!)
statement. Here you can initialise
resources shared between all instances of your server type. The callback
is optional and can be set up in (define-servertype!)
. It should
return zero to indicate success and non-zero to indicate failure. If the
global initialiser fails, Serveez will refuse to register the server type.
(global-finalize #<svz-servertype>)
(serveez-nuke)
) or the
server type gets unregistered for some reason. It should return zero to
signal success. The callback can be set up in (define-servertype!)
and is optional.
(init #<svz-server>)
(define-server!)
and
should return zero to indicate success, otherwise Serveez rejects the
server instance. The callback can be set up in (define-servertype!)
and is optional.
(finalize #<svz-server>)
(define-servertype!)
statement. The callback is optional
and should return zero to indicate success.
(detect-proto #<svz-server> #<svz-socket>)
This callback takes two arguments; the first is the server instance
and the second is the client socket object containing the client
connection information. You can set up this callback in the
(define-servertype!)
statement.
Serveez may invoke this callback several times as data becomes
available from the client until one of the servers recognises it.
The servers can retrieve the data received so far using the
(svz:sock:receive-buffer)
call.
To indicate successful client detection, you need to return a non-zero value. (Note that for historical reasons, this is inconsistent with other functions which return zero on successful completion.) Once the server has indicated success, Serveez invokes any further callbacks for the connection only on that server.
If no server has recognised the client after the first 16 bytes, Serveez will close the connection. The connection will also be closed if the client has not sent enough data for a server to recognise it within 30 seconds of connecting.
If multiple servers are listening on the same network port, Serveez invokes this callback for each of them in an arbitrary order. Only one server at most should indicate successful detection.
This callback is mandatory for servers which get bound to
connection oriented protocol (TCP and PIPE) port configurations by
(bind-server!)
.
(connect-socket #<svz-server> #<svz-socket>)
handle-request
and/or check-request
callback. This can be achieved by calling
(svz:sock:handle-request)
and (svz:sock:check-request)
.
The connect-socket
callback is also mandatory for connection
oriented protocols and must be defined in (define-servertype!)
.
On success you should return zero, otherwise the connection will be
shutdown by Serveez.
(info-server #<svz-server>)
(define-servertype!)
. The returned character string
can be multiple lines separated by \r\n
(but without a trailing
separator). Usually you will return information about the server instance
configuration and/or state.
(info-client #<svz-server> #<svz-socket>)
(define-servertype!)
procedure. It is meant to provide socket
structure specific information. (The socket structure is a client/child
of the given server instance.) You need to return a single line
character string without trailing newlines. The information provided
can be requested by the builtin 4.4.3 Control Protocol Server.
(notify #<svz-server>)
(define-servertype!)
.
(reset #<svz-server>)
SIGHUP
signal which can be issued via `killall -HUP serveez' from user
land. If the underlying operating system does not provide SIGHUP
there is no use for this callback. It provides the possibility to
perform asynchronous tasks scheduled from outside Serveez. You can
optionally set it up in the (define-servertype!)
procedure.
(handle-request #<svz-socket> #<svz-binary> size)
#<svz-binary>
. The size argument is passed for convenience
and specifies the length of the packet in bytes.
The detection, and therefore the invocation, can be made in one of two
ways. When Serveez can determine itself when a packet is complete, the
callback will be invoked directly. Serveez can make this determination
for connections with packet oriented protocols such as UDP and ICMP, or
if you tell Serveez how to parse the packet using
(svz:sock:boundary sock delimiter)
or
(svz:sock:boundary sock size)
and do not specify a
check-request
callback.
Whenever you specify a check-request
callback to determine when
a packet is complete, it becomes the responsiblity of that callback to
invoke handle-request
itself.
Serveez recognises two different return value meanings. For connection oriented protocols (TCP and PIPE), zero indicates success and non-zero failure; on failure, Serveez will shutdown the connection. For packet oriented protocols (UDP and ICMP), a non-zero return value indicates that your server was able to process the passed packet data, otherwise (zero return value) the packet can be passed to other servers listening on the same port configuration.
This callback must be specified in (define-servertype!)
for
packet oriented protocols (UDP and ICMP) but is optional otherwise.
You can modify the callback by calling (svz:sock:handle-request)
.
(check-request #<svz-socket>)
#<svz-socket>
can be obtained
using (svz:sock:receive-buffer)
. The callback is initially not
set and can be set up with (svz:sock:check-request)
. Its purpose
is to check whether a complete request was received. If so, it should
be handled (by running the handle-request
callback) and removed
from the receive buffer (using (svz:sock:receive-buffer-reduce)
).
The callback is for connection oriented protocols (TCP and PIPE) only.
You should return zero to indicate success and non-zero to indicate
failure. On failure Serveez shuts the connection down.
(disconnected #<svz-socket>)
disconnected
callback gets invoked whenever the socket is
lost for some external reason and is going to be shutdown by Serveez.
It can be set up with (svz:sock:disconnected)
.
(kicked #<svz-socket> reason)
(svz:sock:kicked)
. The
reason argument can be either KICK_FLOOD
, indicating the
socket is a victim of the builtin flood protection, or KICK_QUEUE
which indicates a send buffer overflow.
(idle #<svz-socket>)
idle
callback gets invoked from the periodic task scheduler,
which maintains a idle-counter
for each socket structure.
This counter is decremented whenever Serveez becomes idle and the
callback is invoked when it drops to zero. The idle
callback can
set its socket's idle-counter
to some value with the procedure
(svz:sock:idle-counter)
and thus re-schedule itself for a later
task. You can set up this callback with (svz:sock:idle)
.
(trigger-condition #<svz-socket>)
#f
nothing else is happening. Otherwise the
trigger
callback will be invoked immediately. You can set up the
callback using the procedure (svz:sock:trigger-condition)
.
(trigger #<svz-socket>)
trigger
callback is invoked when the trigger-condition
returns #t
. The callback can be set up with the procedure
(svz:sock:trigger)
. Returning a non-zero value shuts the
connection down. A zero return value indicates success. This callback
can be used to perform connection related updates, e.g. you can ensure
a certain send buffer fill.
(check-oob-request #<svz-socket> oob-byte)
(svz:sock:check-oob-request)
. The
oob-byte argument is a number containing the received out-of-band
data byte ranging from 0 to 255. If the callback returns non-zero the
connection will be shutdown. A zero return value indicates success. You
can use (svz:sock:send-oob)
to send a single out-of-band data byte.
Please note: The urgent data is not supported by all operating systems. Also it does not work for all types of network protocols. We verified it to be working for TCP streams on GNU/Linux 2.x.x and Windows 95; let us know if/how it works on other platforms.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
All of the servers listed in 4.4 Existing servers are builtin servers. The following sections describe in detail how to setup a new builtin server type. This kind of server will be part of the Serveez executable. That is why you should make it configurable in the configure script via a `--enable-xxxserver' argument.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Serveez is configured and built via automake and autoconf. That is why you are not supposed to write your own Makefiles but simplified `Makefile.am's. Automake will automatically generate dependencies and compiler/linker command lines. Here are the steps you basically need to follow:
AC_OUTPUT()
statement in `configure.in' which is in the top
level directory. You have to put at least the following into the newly
created `Makefile.am':
noinst_LIBRARIES = libfoo.a libfoo_a_SOURCES = foo-proto.h foo-proto.c INCLUDES = $(SERVEEZ_CFLAGS) -I$(top_srcdir)/src CLEANFILES = *~ MAINTAINERCLEANFILES = Makefile.in |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This file contains at least your server's extern
declaration of your
server definition which must be available from the outside.
The foo
server implements all kinds of
configuration items which can be integers, integer arrays, strings, string
arrays, port configurations, booleans and hash maps. Every item of the server
configuration can later be manipulated from the configuration file.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If you want to define default values for your configuration you have
to define them somewhere and put them into the default configuration
structure. This structure will be used to instantiate your server. For
this example we simply called it simply foo_config
.
In order to associate the configuration items in a server configuration
to keywords within the configuration file you have to define an
array of key-value-pairs. This is done in the foo_config_prototype
field. There are several macros which make different associations. These
are the SVZ_REGISTER_*
macros which take three arguments. The first
argument is the keyword which will occur in the configuration file, the
second is the associated item in your default configuration structure
and the last argument specifies if this item is defaultable or not.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The server definition is in a way the `class' of your server. Together
with the default values (foo_config_prototype
) it serves as a
template for newly instantiated servers. The structure contains a long and a
short description of your server. The short name is used as the prefix for
all server instances of this specific type. The long description is
used in the control protocol (See section 4.4.3 Control Protocol Server.). The server
definition also contains the callbacks your server (mandatorily) provides.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are several callback routines, which get called in order to instantiate the server and for describing the actual behaviour of your server. Here are the description of all of these callbacks. Some of them have to be implemented. Others have reasonable default values.
global initializer (optional)
global finalizer (optional)
instance initializer (mandatory)
instance finalizer (optional)
protocol detection (mandatory)
socket connection (mandatory)
check_request
callback to the default
svz_sock_check_request
which is using the packet delimiter
information to find whole packets. When a client sent such a packet the
handle_request
callback is executed. That is why the foo
server assigns the handle_request
method.
client info (optional)
server info (optional)
\r\n
(no trailing separator). Usually you will return all the
server configuration information.
notifier (optional)
NULL
it is called whenever there is some time
left. It gets the server instance itself as argument. Actually it gets
called every second.
handle request (mandatory for UDP and ICMP servers)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
You distribute your server by editing the `cfgfile.c' file in the
`src/' directory. There you have to include the servers header
file and add the server definition by calling svz_servertype_add()
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The client connection information is stored within the svz_socket_t
object. All of the client connection specific callbacks get this object as
first argument. Following is a description of the most important elements
of this object.
int id
int version
id
and
version
to a coserver you can check if the delivered socket
structure is the original or not within the coserver callback.
int proto
proto
flag determines a server sockets protocol type which can
be PROTO_PIPE
, PROTO_TCP
, PROTO_UDP
,
PROTO_ICMP
or PROTO_RAW
.
int flags
int userflags
char *boundary, int boundary_size
svz_sock_check_request
method to parse packets. These two
properties describe the packet delimiter.
char *send_buffer, int send_buffer_size, int send_buffer_fill
char *recv_buffer, int recv_buffer_size, int recv_buffer_fill
int read_socket (svz_socket_t)
check_request
, but specific
sockets may need other policies.
int write_socket (svz_socket_t)
int disconnected_socket (svz_socket_t)
int connected_socket (svz_socket_t)
svz_tcp_connect
this connection might be established some time later.
This callback gets called when the socket is finally connected.
int kicked_socket (svz_socket_t, int)
int check_request (svz_socket_t)
int handle_request (svz_socket_t, char *, int)
check_request
got a valid packet. The
request arguments contains the actual packet and the second argument is the
length of this packet including the packet delimiter.
int idle_func (svz_socket_t)
idle_counter
(see below) is non-zero, it is decremented and
idle_func
gets called when it drops to zero. idle_func
can
reset idle_counter
to some value and thus can re-schedule itself
for a later task.
int idle_counter
idle_func
.
void *data
NULL
terminated. Some servers store server specific
information here.
void *cfg
svz_sock_detect_proto
has been done cfg
should contain a pointer to the actual
configuration hash map taken from the server instance object.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Coservers are designed to complete blocking tasks. Each coserver runs in
its own thread/process. There are several coservers implemented: the dns,
reverse dns and ident coserver. You need to implement the
callback which gets called when a coserver completed its task. This
routine must be a svz_coserver_handle_result_t
. The first argument is
the actual coserver result which might be NULL
if the request
could not be fulfilled and the latter two arguments are the arguments
you specified yourself when issuing the request. To invoke a coserver
you use one of the svz_coserver_*
macros. The foo server uses
the reverse dns coserver to identify the host name of the remote client.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If you define a server you basically pass an instance name and a list of
items to the (define-server!)
function. Each item has a name and a
value. A value has a type. We provide several types: integers (numbers),
integer arrays, strings, string arrays, booleans (yes/no-values), hashes
(associations) and port configurations.
The following table shows how each kind of value is set up in the configuration file. item is the name of the item to be configured.
(define-port!)
previously and
put its symbolic name into the configuration.The next chapter describes the servers currently implemented using Serveez. The configuration items used by each of them are described in the following format:
NameOfTheItem (Type, default: DefaultValue, Comments)
The example configuration file `data/serveez.cfg' contains an example definition of each server already implemented. You can copy and modify the example for an easy start.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
4.4.1 HTTP Server Integrated Web Server description 4.4.2 IRC Server EFNet IRC Server 4.4.3 Control Protocol Server Serveez control center 4.4.4 Foo Server Example server implementation 4.4.5 SNTP Server Simple network time protocol server 4.4.6 Gnutella Spider Gnutella Client description 4.4.7 Tunnel Server Description of the port forwarder 4.4.8 Chat Server Chat Server (aWCS, textSure) description 4.4.9 Fake Ident Server Description of a simple ident server 4.4.10 Passthrough Server Description of the program passthrough server 4.4.11 Mandel Server Distributed Mandelbrot server
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The integrated HTTP server was originally meant to be a simple but fast document server. But now it can even execute CGI scripts. The GET, HEAD and POST methods are fully functional. Additionally Serveez produces directory listings when no standard document file (e.g. `index.html') has been found at the requested document node (directory). Furthermore it implements a file cache for speeding up repetitive HTTP request.
In comparison to other web server projects like Apache and Roxen this web server is really fast. Comparative benchmarks will follow. The benchmark system is a 233 MHz Mobile Pentium MMX. Both the server and the client (http_load - multiprocessing http test client) ran on the same computer.
Small files
concurrent fetches 1 10 50 100 200 500 1000 hits/second 501 520 481 475 420 390 295 |
CGI
Large files
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following options can be set from the configuration file.
indexfile (string, default: index.html)
indexfile
parameter is the default file served by the HTTP
server when the user does not specify a file but a document node
(e.g. http://www.textsure.net/).
docs (string, default: ../show)
docs
parameter is the document root where the server finds its
web documents.
userdir (string, default: public_html)
cgi-url (string, default: /cgi-bin)
cgi-dir
(see below) and pipes its output to the user.
cgi-dir (string, default: ./cgibin)
cgi-dir
is the CGI document root (on the server).
cgi-application (hash, default: empty)
cache-size (integer, default: 200 kb)
cache-entries (integer, default: 64)
cache-size
and cache-entries
to zero.
timeout (integer, default: 15)
timeout
value is the amount of time in seconds after which
a keep-alive connection (this is a HTTP/1.1 feature) will be closed when
it has been idle.
keepalive (integer, default: 10)
keepalive
documents at all. Then the connection will be closed.
Both this and the timeout
value are just to be on the safe side.
They protect against idle and high traffic connections.
default-type (string, default: text/plain)
default-type
is the default content type the HTTP server
assumes if it can not identify a served file by the types
hash
and the type-file
(see below).
type-file (string, default: /etc/mime.types)
types (hash, default: empty)
admin (string, default: root@localhost)
host (string, default: localhost)
nslookup (boolean, default: false)
ident (boolean, default: false)
logfile (string, default: http-access.log)
logformat (string, default: CLF)
CLF = host ident authuser date request status bytes |
%h (host)
%i (ident)
%u (authuser)
%t (date)
date = [day/month/year:hour:minute:second zone] day = 2*digit month = 3*letter year = 4*digit hour = 2*digit minute = 2*digit second = 2*digit zone = (`+' | `-') 4*digit |
%R (request)
%r (referrer)
%a (agent)
%c (status)
%l (bytes)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Internet Relay Chat. The mother of all chat systems. The integrated IRC server is intended to be compatible with the EFNet. There are no good possibilities to test this in real life, so it is still under heavy construction. But it can be used as a standalone server anyway.
IRC itself is a teleconferencing system, which (through the use of the client-server model) is well-suited for running on many machines in a distributed fashion. A typical setup involves a single process (the server) forming a central point for clients (or other servers) to connect to, performing the required message delivery/multiplexing and other functions.
The server forms the backbone of IRC, providing a point for clients and servers to connect to. Clients connect to talk to each other. Servers connect to build up a network of servers. IRC server connections have to build up a spanning tree. Loops are not allowed. Each server acts as a central node for the rest of the network it sees.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following table shows the configuration keys provided. Most of the configuration items are similar to those of an Hybrid IRC server. They seem archaic at first sight but IRC operators are used to it. Refer to the Hybrid documentation for further information. It can be found on the EFNet web page.
MOTD-file (string, default: ../data/irc-MOTD.txt)
INFO-file (string, default: no file)
INFO-file
s content gets displayed when the user issues the
/INFO command.
tsdelta (integer, default: 0)
channels-per-user (integer, default: 10)
admininfo (string, no default)
M-line (string, no default, mandatory)
":" virtual hostname ":" optional bind address (real hostname) ":" server info: "World's best IRC server" ":" port |
A-line (string, no default, mandatory)
":" administrative info (department, university) ":" the server's geographical location ":" email address for a person responsible for the IRC server |
Y-lines (string array, no default, suggested)
":" class number (higher numbers refer to a higher priority) ":" ping frequency (in seconds) ":" connect frequency in seconds for servers, 0 for client classes ":" maximum number of links in this class ":" send queue size |
I-lines (string array, no default, mandatory)
":" user@ip, you can specify `NOMATCH' here to force matching user@host ":" password (optional) ":" user@host ":" password (optional) ":" connection class number (YLine) |
O-lines (string array, no default, optional)
":" user@host, user@ forces checking ident ":" password ":" nick |
o-lines (string array, no default, optional)
":" user@host, user@ forces checking ident ":" password ":" nick |
C-lines (string array, no default, networked)
":" host name ":" password ":" server name (virtual) ":" port (if not given we will not connect) ":" connection class number (YLine) |
N-lines (string array, no default, networked)
":" host name ":" password ":" server name (virtual host name) ":" password ":" how many components of your own server's name to strip off the front and be replaced with a `*'. ":" connection class number (YLine) |
K-lines (string array, no default, optional)
":" host ":" time of day ":" user |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Serveez implements something like a telnet protocol for administrative purposes. You just need to start a telnet session like:
$ telnet www.textsure.net 42420 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
File Size Usage Hits Recent Ready zlib-1.1.3-20000531.zip 45393 0 0 1 Yes texinfo.tex 200531 0 0 2 Yes shayne.txt 2534 0 1 1 Yes Total : 248458 byte in 3 cache entries |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There is nothing to be configured yet.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
port (port configuration, default: tcp, 42421, *)
bar (integer, no default)
reply (string, default: Default reply)
messages (string array, default: ...)
ports (integer array, default: 1, 2, 3, 4)
assoc (hash, default, default: ...)
truth (boolean, default: true)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This protocol provides a site-independent, machine readable date and time. The Time service sends back time in seconds since midnight on January first 1900.
One motivation arises from the fact that not all systems have a date/time clock, and all are subject to occasional human or machine error. The use of time-servers makes it possible to quickly confirm or correct a system's idea of the time, by making a brief poll of several independent sites on the network.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The configuration of this server does not require any item.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This Gnutella spider is for seeking the needle in the haystack. Once connected to the network it regularly tries to find certain files in there. It keeps track of all connected clients and tries to reconnect them if the current connections are lost.
Gnutella, however has nothing to do with the GNU project. The original client is just a free (as in free beer) piece of software. With Serveez you have a free (as in freedom) way to use it. Have a look at the Gnutella page for further information.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
net-url (string, default: gnutella-net)
host:port
combinations
depend on the bindings.
hosts (string array, no default)
ip:port
(e.g. `146.145.85.34:6346'). You can also pass Internet
host names. If the port information is left blank it defaults to 6346. If
you need some entry point for the Gnutella network have a look at
http://www.gnutellahosts.com/ or http://www.gnutellanet.com/.
search (string array, default: Puppe3000, Meret Becker)
search-limit (integer, default: 30)
max-ttl (integer, default: 5)
max-ttl
the ttl value is set to max-ttl
. This is
necessary since most people use far too large TTL values.
ttl (integer, default: 5)
download-path (string, default: /tmp)
share-path (string, default: /tmp)
max-downloads (integer, default: 4)
max-uploads (integer, default: 4)
connection-speed (integer, default: 28)
min-speed (integer, default: 28)
file-extensions (string array, default: empty list)
connections (integer, default: 4)
force-ip (string, default: not set)
force-port (integer, default: not set)
force-port
as port information. See above for more information.
disable (boolean, default: false)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Forwarding between the same types of connection is always possible. When forwarding to an ICMP tunnel we use a special protocol which we will outline in the following section.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When receiving an ICMP packet it also contains the IP header. When sending an ICMP packet you must not prepend this IP header. The kernel will do this itself. The IP header always follows the actual ICMP header followed by the ICMP packet data. Since this section does not cover raw sockets we leave the IP header structure out here.
The modified ICMP message format is as:
Offset | Size | Meaning |
0 | 1 | Message type. |
1 | 1 | Message type sub code. |
2 | 2 | Checksum. |
4 | 2 | Senders unique identifier. |
6 | 2 | Sequence number. |
8 | 2 | Port number. |
10 | 0 - 65506 | Packet load. |
Each of these fields can be modified and processed by Serveez and do not get touched by the kernel at all. The ICMP socket implementation of Serveez differentiates two types of sockets: listening and connected ICMP sockets. This is non-standard because it actually makes no sense since there is no difference for the kernel. The introduction of these semantics allow Serveez to forward data between connection-oriented (TCP and named pipes) and packet-oriented (UDP and ICMP) protocols.
ICMP_SERVEEZ
) by default.
Sub code | Constant identifier | Description |
0 | ICMP_SERVEEZ_DATA | packet contains data |
1 | ICMP_SERVEEZ_REQ | unused |
2 | ICMP_SERVEEZ_ACK | unused |
3 | ICMP_SERVEEZ_CLOSE | disconnection message |
4 | ICMP_SERVEEZ_CONNECT | connect message |
Except the data message type subcode all ICMP packets created and sent by
Serveez have a zero payload. The connect message subcode identifies a
new connection and the disconnection message subcode its shutdown without
actually transmitting data. These two subcodes emulate a TCP connections
connect()
, accept()
and shutdown()
system call.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
source (port configuration, no default)
target (port configuration, no default)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The whole Serveez package was originally written by Martin Grabmueller as a fast C backend for a chat system (now called textSure). This can be found at http://www.textsure.net/. The server implements two kinds of protocols. One is for the master server which does all the administrative stuff. The second is for the chat clients (applets or bots). Basically the chat server is a simple multicast unit.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The first character is one of the following and has a special meaning:
Character | Meaning |
0 | Send message to all clients. |
1 | Send message to the clients denoted in the message. |
2 | Report status to the master server. |
3 | Kick the clients denoted in the message. |
4 | Turn off flood protection for the clients in the message. |
5 | Turn on flood protection for the clients in the message. |
6 | Initialization message. |
Those special characters are followed by a single space.
Messages which require additional parameters (multicast for example) carry these parameters after the space in a comma separated list of client ids in the format mentioned above. The client id list is terminated by the \0 character terminating the request (if no parameters follow) or by a single space (if parameters follow). Note that no spaces are allowed in comma separated lists.
Examples: 0 Hallo Welt\0 - Send "Hallo Welt\0" to all clients except the master server. 1 1,4,6 Gruezi!\0 - Send "Gruezi\0" to the clients 1, 4 and 6. 2 \0 - Send status data back to the master server. 3 3,4\0 - Kicks clients 3 and 4. 4 4,16\0 - Turn off flood protection for clients 4 and 16. 5 1,5\0 - Turn on flood protection for clients 1 and 5. 6 \0 - Initialize data structures and accept the connection as the master server. |
Status messages have the same format as other client messages for the master server. The client number in the message is the id of the master server itself, followed by a space, the status message type and additional parameters.
Type | Description | Parameter |
0 | Client has connected. | Client id, client IP number:port |
1 | Client has disconnected. | Client id, error code |
2 | Client got kicked. | Client id, kick reason |
3 | Low level server is alive. | 42 |
4 | Notify time elapsed. | 42 |
Error code | Description |
0 | Success |
1 | Client closed connection |
Kick reason | Description |
0 | Flooding |
1 | Output buffer overflow |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There is nothing to be configured yet. You should notice that it is possible to bind this server to both named pipes and TCP ports.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Most systems run the 'ident protocol' on port 113. Internet hosts can connect to that port and find out what user is having a connection to the host. For example a webserver can query your username when you fetch a file (e.g. Serveez' internal ident-coserver can do that). Most IRC servers protect themselves by allowing only users that have a valid ident response. Therefore mIRC (for windoze) has a built in ident server. This fake ident server can be used to 'fake' a response. This is useful when you connect through a masquerading gateway and the gateway cannot handle ident requests correctly. (Or, of course, you are using windoze, need an ident response and do not have mIRC at hand.)
This server has two modes of operation. In one mode all requests get "ERROR : NO-USER" as response. This is a valid but not very helpful response. The other mode makes the server send a valid and useful response. It contains a system type and a username. The system type is usually 'UNIX'. Others are valid but never used (at least i have never seen something else).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This server is easy to configure.
systemtype (string, default: UNIX)
username (string, default: <NULL>)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
binary (string, no default)
directory (string, no default)
user (string, no default)
argv (string array, no default)
binary
parameter.
do-fork (boolean, default: true)
fork()
and exec()
method. Otherwise it will pass the data through a unnamed pair of
sockets [ or two pairs of anonymous pipes ].
single-threaded (boolean, default: true)
thread-frequency (integer, default: 40)
thread-frequency
parameter specifies the maximum number
of program instances that may be spawned from the server within an interval
of 60 seconds.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ Example Mandelbrot picture. ]
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It implements a protocol called `dnc'. `dnc' - short for "Distributed Number Cruncher". The Mandelbrot server manages the computation of a graphic visualization of the Mandelbrot set fractal. Each client can connect to the server and ask for something to calculate and is meant to send its result back to the server. Finally the server produces a bitmap in the XPM format and uses a specified viewer application to bring it onto your screen.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
start (string, default: -2.0-1.5i)
end (string, default: +1.1+1.5i)
x-res (integer, default: 320)
y-res (integer, default: 240)
colors (integer, default: 256)
outfile (string, default: mandel.xpm)
viewer (string, default: xv)
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |