Next: Builtin servers, Previous: Embedded servers, Up: Writing servers [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.
Return a list of symbols representing the features of the underlying libserveez. For details, See Library features.
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.
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 procedures for strings and lists
which help to process this binary data in a more complex (guile’ish) way.
Convert the given binary smob binary into a string. Return the string itself.
Convert the given string into a binary smob. The data pointer of
the binary smob is marked as garbage which must be free
’d in the
sweep phase of the garbage collector.
Return #t
if obj is an instance of the binary smob type.
Convert the scheme list list into a binary smob. Each of the elements of list is checked for validity. The elements can be either exact numbers in a byte’s range or characters.
Convert the given binary smob binary into a scheme list. The list is empty if the size of binary is zero.
Search through the binary smob binary for needle,
which can be an exact number, character,
string or another binary smob. Return #f
if the needle could
not be found, or a positive number indicating the position of the first
occurrence of needle in the binary smob binary.
Set the byte at position index of the binary smob binary to the value given in value which can be either a character or an exact number.
Obtain the byte at position index of the binary smob binary.
Return the size in bytes of the binary smob binary.
Append either the binary smob or string append onto the binary
smob binary. If binary has been a simple data pointer
reference it is then a standalone binary smob as returned by
string->binary
.
Create a subset binary smob from the given binary smob binary. The
range of this subset is specified by start and end both
inclusive (thus the resulting size is end - start + 1
).
With a single exception: If end is not given or specified with -1,
return all data until the end of binary.
Return a new binary smob with the reverse byte order of the given binary smob binary.
Perform an in-place reversal of the given binary smob binary and return it.
Return the long
value of the binary
smob binary at the array index index.
Set the long
value of the binary smob binary
at the array index index to the given value value.
Return the previous (overridden) value.
Return the int
value of the binary
smob binary at the array index index.
Set the int
value of the binary smob binary
at the array index index to the given value value.
Return the previous (overridden) value.
Return the short
value of the binary
smob binary at the array index index.
Set the short
value of the binary smob binary
at the array index index to the given value value.
Return the previous (overridden) value.
Return the char
value of the binary
smob binary at the array index index.
Set the char
value of the binary smob binary
at the array index index to the given value value.
Return the previous (overridden) value.
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)) ))))
Define a new server type based on args. (If everything
works fine you have a freshly registered server type afterwards.)
Return #t
on success.
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.
Return #t
if the given cell sock is an instance of a valid
#<svz-socket>
, otherwise #f
.
Set the check-request
member of the socket structure sock
to proc. Return the previously handler if there is any.
Set the check-oob-request
callback of the given socket
structure sock to proc, returning
the previous callback (if there was any set before).
The callback is run whenever urgent data (out-of-band)
has been detected on the socket.
Send byte oob as urgent (out-of-band) data through the
underlying TCP stream of TCP sock.
Return #t
on successful completion and otherwise
(either it failed to send the byte or the passed socket is not a TCP
socket) #f
.
Set the handle-request
member of the socket structure sock
to proc. Return the previously set handler if there is any.
Setup the packet boundary of the socket sock. The given string
value boundary can contain any kind of data. If boundary
is an exact number, set up the socket to parse fixed sized packets.
More precisely, set the check-request
callback of the given
socket structure sock to an internal routine which runs the
socket’s handle-request
callback when it detects a
complete packet specified by boundary.
For instance, you can arrange for Serveez to pass the
handle-request
procedure lines of text by calling
(svz:sock:boundary sock "\n")
.
Set or unset the flood protection bit of the given socket sock.
Return the previous value of this bit (#t
or #f
). The
flag argument must be either boolean or an exact number and is
optional.
Write buffer (string or binary smob) to the socket sock.
Return #t
on success and #f
on failure.
Schedule the socket sock for shutdown after all data
within the send buffer queue has been sent. You should call this
right before the last call to svz:sock:print
.
Turn the Nagle algorithm for the TCP socket sock on or off depending
on the optional enable argument. Return the previous state of this
flag (#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.
Return the send buffer of the socket sock as a binary smob.
Return the current send buffer size and fill status in bytes of the socket sock as a pair of exact numbers. If the optional argument size is given, set the send buffer to the specified size in bytes.
Return the receive buffer of the socket sock as a binary smob.
Return the current receive buffers size and fill status in bytes of the socket sock as a pair of exact numbers. If the optional argument size is given, set the receive buffer to the specified size in bytes.
Dequeue length bytes from the receive buffer of the socket sock, or all bytes if length is omitted. Return the number of bytes actually shuffled away.
Establish a network connection to the given host [ :port ].
If proto equals 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 block.
The port argument must be an exact number in the range from
0 to 65535, also in host byte order. Return a valid #<svz-socket>
or #f
on failure.
Set the disconnected-socket
member of the socket structure
sock to proc. The given callback
runs whenever the socket is lost for some external reason.
Return the previously set handler if there is one.
Set the kicked-socket
callback of the given socket structure
sock to proc and return any previously
set procedure. This callback gets called whenever the socket gets
closed by Serveez intentionally.
Set the trigger
callback of the socket structure sock to
proc and return any previously set procedure.
The callback is run when the trigger-condition
callback returns
#t
.
Set the trigger-condition
callback for the socket
structure sock to proc. Return the
previously set procedure if available. The callback is run once every
server loop indicating whether the trigger
callback should be
run or not.
Set the idle
callback of the socket structure
sock to proc. Return 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.
Return the socket structure sock’s current
idle-counter
value. If the optional argument counter is
given, the set the idle-counter
. Please have a look at the
svz:sock:idle
procedure for the exact meaning of this value.
Return the given socket’s sock parent and optionally set it to the
socket parent. Return either a valid
#<svz-socket>
object or an empty list.
Return the given socket’s sock referrer and optionally set it to the
socket referrer. Return either a valid
#<svz-socket>
or an empty list.
Return the #<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.
Return the current local address as a pair like
(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.
Return the current remote address as a pair like
(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.
Return the #<svz-socket>
specified by ident,
a pair of integers in the form (identification . version)
.
If that socket no longer exists, return #f
.
Return a pair of numbers identifying the given
#<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.
Return one of the 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, return #f
.
Return either a binary smob containing a data block read from the open input port port with a maximum number of size bytes, or the end-of-file object if the underlying ports end has been reached. The size of the returned binary smob may be less than the requested size size if it exceed the current size of the given port port. Throw an exception if an error occurred while reading from the port.
Return #t
if the given cell server is an instance of a valid
#<svz-server>
, otherwise #f
.
Return a list of listening #<svz-socket>
smobs to which the
given server instance server is currently bound, or an empty list
if there is no such binding yet.
Return a list of #<svz-socket>
client smobs associated with
the given server instance server in arbitrary order, or an
empty list if there is no such client.
Return the configuration item specified by key of the given server
instance server. You can pass this procedure a socket, too, in
which case the appropriate server instance is looked up. If the given
string key is invalid (not defined in the configuration alist in
define-servertype!
), then return an empty list.
Return #t
if the given string name corresponds with a
registered port configuration, otherwise #f
.
Check whether the given string name corresponds with an
instantiated server name and return #t
if so.
Check whether the given string name is a valid
server type prefix known in Serveez and return #t
if so.
Otherwise return #f
.
Control the use of exception handlers for the Guile procedure calls of
Guile server callbacks. If the optional argument enable is
#t
, enable exception handling; if #f
, disable it.
Return the current (boolean) setting.
Shutdown all network connections and terminate after the next event
loop. You should use this instead of calling quit
.
Optional arg exit-value specifies an exit value for the
serveez program. It is mapped to a number via scm_exit_value
.
Make the search path for the Serveez core library accessible to Scheme. Return a list a each path as previously defined. If args is specified, override the current definition of this load path with it. The load path is used to tell Serveez where it can find additional server modules.
Make the list of local interfaces accessible to Scheme. Return the local interfaces as a list of ip addresses in dotted decimal form. If args are specified, they are added as additional local interfaces.
Lookup a network rpc service arg (name or service number),
and return a network rpc service object.
If given no arguments, it behave like getrpcent
.
Open and rewind 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 calling endrpcent
. Otherwise it is
equivalent to calling setrpcent
with arg 1.
Establish a (portmap service) mapping
between the triple [prognum,versnum,protocol] and
port on the machine’s portmap service. The value of protocol
is most likely IPPROTO_UDP
or IPPROTO_TCP
.
If instead protocol and port are omitted, destroy
all mapping between the triple [prognum,versnum,*] and ports
on the machine’s portmap service.
Return a list of the current RPC program-to-port mappings on the host located at IP address address, which defaults to the local machine’s IP address. Return an empty list if either there is no such list available or an error occurred while fetching the list.
Enqueue the host string argument into the internal
DNS coserver queue. When the coserver responds, the procedure
callback is run as (callback addr)
. The addr
argument passed to the callback is a string representing the appropriate
IP address for the given hostname host.
Enqueue the given addr argument, which must be
an IP address in network byte order, into the internal reverse DNS coserver
queue. When the coserver responds, the procedure callback is
run as (callback host)
where host is the hostname of the
requested IP address addr.
Enqueue the given #<svz-socket>
sock into the
internal ident coserver queue. When the coserver responds, it
runs the procedure callback as (callback user)
, where
user is the corresponding username for the client connection
sock.
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.
This callback is invoked once for every type of server right after
the 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.
If you want to free shared resources, which were possibly allocated
within the global initialiser, you can do so here. The callback is
invoked when Serveez shuts down (issued by 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.
Within this callback you can initialise everything you might need for
a single instance of your server. The callback is invoked for each
server instance which has been created by 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.
The server instance finaliser gets its instance representation passed
as argument. You need to free all resources used by this server
instance which might have been allocated within the server instance
initialiser or consumed while running. You can set this callback in
the define-servertype!
statement. The callback is optional
and should return zero to indicate success.
Connection oriented protocols like TCP and PIPE allow more than one server to be listening on the same network port. Therefore, it is necessary to be able to detect the type of client connecting to a port.
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 procedures 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!
.
If the client detection signalled success, this callback is invoked to
assign the client connection to a server instance. The arguments are
the same as the detection callback. In this callback you can assign
all the connection specific callbacks for your server and perform some
initial tasks. Basically you should specify the 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.
This callback gets invoked when requested by the builtin
Control Protocol Server. The callback is optional and can be
set up in 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.
This callback is optional. You can set it up in the
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 Control Protocol Server.
The server instance notifier callback will be invoked whenever there is idle
time available. In practice, it is run approximately once a second.
A server instance can use it to perform periodic tasks. The callback
is optional and can be set up in define-servertype!
.
This callback is invoked when the Serveez process receives a 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.
This callback is invoked whenever a complete packet has been detected
in the receive buffer. The packet data is passed to the callback as a
#<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
.
This callback is invoked whenever new data has arrived in the receive buffer.
The receive buffer of the given #<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.
The 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
.
This callback gets invoked whenever the socket gets closed by Serveez
intentionally. It can be set up with 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.
The 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
.
This callback is invoked once every server loop for the socket structure.
If you return #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
.
The 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.
This callback is invoked whenever urgent data (out-of-band) has been detected
on a socket. Initially this event is ignored and the callback can be set
up with the procedure 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.
Next: Builtin servers, Previous: Embedded servers, Up: Writing servers [Contents][Index]