-<!-- $Header: /home/cvsroot/yaz/doc/frontend.xml,v 1.1 2001-01-04 13:36:24 adam Exp $ -->
-<chapter><title id="server">Making an IR Server for Your Database</title>
-
-<sect1><title>Introduction</title>
-
-<para>
-If you aren't into documentation, a good way to learn how the
-backend interface works is to look at the <filename>backend.h</filename>
-file. Then, look at the small dummy-server in
-<filename>server/ztest.c</filename>. Finally, you can have a look at
-the <filename>seshigh.c</filename> file, which is where most of the
-logic of the frontend server is located. The <filename>backend.h</filename>
-file also makes a good reference, once you've chewed your way through
-the prose of this file.
-</para>
-
-<para>
-If you have a database system that you would like to make available by
-means of Z39.50/SR, &yaz; basically offers your two options. You
-can use the APIs provided by the &asn;, &odr;, and &comstack;
-modules to
-create and decode PDUs, and exchange them with a client. Using this
-low-level interface gives you access to all fields and options of the
-protocol, and you can construct your server as close to your existing
-database as you like. It is also a fairly involved process, requiring
-you to set up an event-handling mechanism, protocol state machine,
-etc. To simplify server implementation, we have implemented a compact
-and simple, but reasonably full-functioned server-frontend that will
-handle most of the protocol mechanics, while leaving you to
-concentrate on your database interface.
-</para>
-
-<note>
-<para>
-The backend interface was designed in anticipation of a specific
-integration task, while still attempting to achieve some degree of
-generality. We realise fully that there are points where the
-interface can be improved significantly. If you have specific
-functions or parameters that you think could be useful, send us a
-mail (or better, sign on to the mailing list referred to in the
-toplevel README file). We will try to fit good suggestions into future
-releases, to the extent that it can be done without requiring
-too many structural changes in existing applications.
-</para>
-</note>
-</sect1>
-
-<sect1><title>The Database Frontend</title>
-
-<para>
-We refer to this software as a generic database frontend. Your
-database system is the <emphasis>backend database</emphasis>, and the
-interface between the two is called the <emphasis>backend API</emphasis>.
-The backend API consists of a small number of function prototypes and
-structure definitions. You are required to provide the
-<function>main()</function> routine for the server (which can be
-quite simple), as well as functions to match each of the prototypes.
-The interface functions that you write can use any mechanism you like
-to communicate with your database system: You might link the whole
-thing together with your database application and access it by
-function calls; you might use IPC to talk to a database server
-somewhere; or you might link with third-party software that handles
-the communication for you (like a commercial database client library).
-At any rate, the functions will perform the tasks of:
-</para>
-
-<itemizedlist>
-
-<listitem><para>
-Initialization.
-</para></listitem>
-
-<listitem><para>
-Searching.
-</para></listitem>
-
-<listitem><para>
-Fetching records.
-</para></listitem>
-
-<listitem><para>
-Scanning the database index (if you wish to implement SCAN).
-</para></listitem>
-
-</itemizedlist>
-
-<para>
-(more functions will be added in time to support as much of
-Z39.50-1995 as possible).
-</para>
-
-<para>
-Because the model where pipes or sockets are used to access the backend
-database is a fairly common one, we have added a mechanism that allows this
-communication to take place asynchronously. In this mode, the frontend
-server doesn't have to block while the backend database is processing
-a request, but can wait for additional PDUs from the client.
-</para>
-
-</sect1>
-<sect1><title>The Backend API</title>
-
-<para>
-The headers files that you need to use the interface are in the
-<filename>include/yaz</filename> directory. They are called
-<filename>statserv.h</filename> and <filename>backend.h</filename>. They
-will include other files from the <filename>include/yaz</filename>
-directory, so you'll probably want to use the -I option of your
-compiler to tell it where to find the files. When you run
-<literal>make</literal> in the toplevel &yaz; directory,
-everything you need to create your server is put the
-<filename>lib/libyaz.a</filename> library.
-</para>
-</sect1>
-
-<sect1><title>Your main() Routine</title>
-
-<para>
-As mentioned, your <function>main()</function> routine can be quite brief.
-If you want to initialize global parameters, or read global configuration
-tables, this is the place to do it. At the end of the routine, you should
-call the function
-</para>
-
-<synopsis>
- int statserv_main(int argc, char **argv);
-</synopsis>
-
-<para>
-<function>statserv_main</function> will establish listening sockets
-according to the parameters given. When connection requests are received,
-the event handler will typically <function>fork()</function> to handle the
-new request. If you do use global variables, you should be aware, then,
-that these cannot be shared between associations, unless you explicitly
-disallow forking by command line parameters (we advise against this for
-any purposes except debugging, as a crash or hang in the server process
-will affect all users currently signed on to the server).
-</para>
-
-<para>
-The server provides a mechanism for controlling some of its behavior
-without using command-line options. The function
-</para>
-
-<synopsis>
- statserv_options_block *statserv_getcontrol(void);
-</synopsis>
-
-<para>
-Will return a pointer to a <literal>struct statserv_options_block</literal>
-describing the current default settings of the server. The structure
-contains these elements:
-
-<variablelist>
-<varlistentry><term>int dynamic</term><listitem><para>
-A boolean value, which determines whether the server
-will fork on each incoming request (TRUE), or not (FALSE). Default is
-TRUE.
-</para></listitem></varlistentry>
-<varlistentry><term>int loglevel</term><listitem><para>
-Set this by ORing the constants defined in
-<filename>include/yaz/yaz-log.h</filename>.
-</para></listitem></varlistentry>
-<varlistentry><term>char logfile[ODR_MAXNAME+1]</term>
-<listitem><para>File for diagnostic output ("": stderr).
-</para></listitem></varlistentry>
-<varlistentry><term>char apdufile[ODR_MAXNAME+1]</term>
-<listitem><para>
-Name of file for logging incoming and outgoing APDUs ("": don't
-log APDUs, "-": <literal>stderr</literal>).
-</para></listitem></varlistentry>
-<varlistentry><term>char default_listen[1024]</term>
-<listitem><para>Same form as the command-line specification of
-listener address. "": no default listener address.
-Default is to listen at "tcp:@:9999". You can only
-specify one default listener address in this fashion.
-</para></listitem></varlistentry>
-<varlistentry><term>enum oid_proto default_proto;</term>
-<listitem><para>Either <literal>PROTO_SR</literal> or
-<literal>PROTO_Z3950</literal>. Default is <literal>PROTO_Z39_50</literal>.
-</para></listitem></varlistentry>
-<varlistentry><term>int idle_timeout;</term>
-<listitem><para>Maximum session idletime, in minutes. Zero indicates
-no (infinite) timeout. Default is 120 minutes.
-</para></listitem></varlistentry>
-<varlistentry><term>int maxrecordsize;</term>
-<listitem><para>Maximum permissible record (message) size. Default
-is 1Mb. This amount of memory will only be allocated if a client requests a
-very large amount of records in one operation (or a big record). Set it
-to a lower number
-if you are worried about resource consumption on your host system.
-</para></listitem></varlistentry>
-<varlistentry><term>char configname[ODR_MAXNAME+1]</term>
-<listitem><para>Passed to the backend when a new connection is received.
-</para></listitem></varlistentry>
-<varlistentry><term>char setuid[ODR_MAXNAME+1]</term>
-<listitem><para>Set user id to the user specified, after binding
-the listener addresses.
-</para></listitem></varlistentry>
-</variablelist>
-</para>
-
-<para>
-The pointer returned by <literal>statserv_getcontrol</literal> points to
-a static area. You are allowed to change the contents of the structure,
-but the changes will not take effect before you call
-</para>
-
-<synopsis>
- void statserv_setcontrol(statserv_options_block *block);
-</synopsis>
-
-<note>
-<para>
-that you should generally update this structure before calling
-<function>statserv_main()</function>.
-</para>
-</note>
-</sect1>
-
-<sect1><title>The Backend Functions</title>
-
-<para>
-For each service of the protocol, the backend interface declares one or
-two functions. You are required to provide implementations of the
-functions representing the services that you wish to implement.
-</para>
-
-<synopsis>
- bend_initresult *bend_init(bend_initrequest *r);
-</synopsis>
-
-<para>
-This function is called once for each new connection request, after
-a new process has been forked, and an initRequest has been received
-from the client. The parameter and result structures are defined as
-</para>
-
-<synopsis>
+<!-- $Id: frontend.xml,v 1.12 2002-05-30 20:57:38 adam Exp $ -->
+ <chapter id="server"><title>Generic server</title>
+ <sect1><title>Introduction</title>
+
+ <para>
+ If you aren't into documentation, a good way to learn how the
+ back end interface works is to look at the <filename>backend.h</filename>
+ file. Then, look at the small dummy-server in
+ <filename>ztest/ztest.c</filename>. The <filename>backend.h</filename>
+ file also makes a good reference, once you've chewed your way through
+ the prose of this file.
+ </para>
+
+ <para>
+ If you have a database system that you would like to make available by
+ means of Z39.50, &yaz; basically offers your two options. You
+ can use the APIs provided by the &asn;, &odr;, and &comstack;
+ modules to
+ create and decode PDUs, and exchange them with a client.
+ Using this low-level interface gives you access to all fields and
+ options of the protocol, and you can construct your server as close
+ to your existing database as you like.
+ It is also a fairly involved process, requiring
+ you to set up an event-handling mechanism, protocol state machine,
+ etc. To simplify server implementation, we have implemented a compact
+ and simple, but reasonably full-functioned server-frontend that will
+ handle most of the protocol mechanics, while leaving you to
+ concentrate on your database interface.
+ </para>
+
+ <note>
+ <para>
+ The backend interface was designed in anticipation of a specific
+ integration task, while still attempting to achieve some degree of
+ generality. We realize fully that there are points where the
+ interface can be improved significantly. If you have specific
+ functions or parameters that you think could be useful, send us a
+ mail (or better, sign on to the mailing list referred to in the
+ top-level README file). We will try to fit good suggestions into future
+ releases, to the extent that it can be done without requiring
+ too many structural changes in existing applications.
+ </para>
+ </note>
+ </sect1>
+
+ <sect1 id="server.frontend"><title>The Database Frontend</title>
+
+ <para>
+ We refer to this software as a generic database frontend. Your
+ database system is the <emphasis>backend database</emphasis>, and the
+ interface between the two is called the <emphasis>backend API</emphasis>.
+ The backend API consists of a small number of function handlers and
+ structure definitions. You are required to provide the
+ <function>main()</function> routine for the server (which can be
+ quite simple), as well as a set of handlers to match each of the prototypes.
+ The interface functions that you write can use any mechanism you like
+ to communicate with your database system: You might link the whole
+ thing together with your database application and access it by
+ function calls; you might use IPC to talk to a database server
+ somewhere; or you might link with third-party software that handles
+ the communication for you (like a commercial database client library).
+ At any rate, the handlers will perform the tasks of:
+ </para>
+
+ <itemizedlist>
+
+ <listitem><para>
+ Initialization.
+ </para></listitem>
+
+ <listitem><para>
+ Searching.
+ </para></listitem>
+
+ <listitem><para>
+ Fetching records.
+ </para></listitem>
+
+ <listitem><para>
+ Scanning the database index (optional - if you wish to implement SCAN).
+ </para></listitem>
+
+ <listitem><para>
+ Extended Services (optional).
+ </para></listitem>
+
+ <listitem><para>
+ Result-Set Delete (optional).
+ </para></listitem>
+
+ <listitem><para>
+ Result-Set Sort (optional).
+ </para></listitem>
+
+ </itemizedlist>
+
+ <para>
+ (more functions will be added in time to support as much of
+ Z39.50-1995 as possible).
+ </para>
+
+ </sect1>
+ <sect1 id="server.backend"><title>The Backend API</title>
+
+ <para>
+ The header file that you need to use the interface are in the
+ <filename>include/yaz</filename> directory. It's called
+ <filename>backend.h</filename>. It will include other files from
+ the <filename>include/yaz</filename> directory, so you'll
+ probably want to use the -I option of your compiler to tell it
+ where to find the files. When you run
+ <literal>make</literal> in the top-level &yaz; directory,
+ everything you need to create your server is to link with the
+ <filename>lib/libyaz.la</filename> library.
+ </para>
+ </sect1>
+
+ <sect1 id="server.main"><title>Your main() Routine</title>
+
+ <para>
+ As mentioned, your <function>main()</function> routine can be quite brief.
+ If you want to initialize global parameters, or read global configuration
+ tables, this is the place to do it. At the end of the routine, you should
+ call the function
+ </para>
+
+ <synopsis>
+int statserv_main(int argc, char **argv,
+ bend_initresult *(*bend_init)(bend_initrequest *r),
+ void (*bend_close)(void *handle));
+ </synopsis>
+
+ <para>
+ The third and fourth arguments are pointers to handlers. Handler
+ <function>bend_init</function> is called whenever the server receives
+ an Initialize Request, so it serves as a Z39.50 session initializer. The
+ <function>bend_close</function> handler is called when the session is
+ closed.
+ </para>
+
+ <para>
+ <function>statserv_main</function> will establish listening sockets
+ according to the parameters given. When connection requests are received,
+ the event handler will typically <function>fork()</function> and
+ create a sub-process to handle a new connection.
+ Alternatively the server may be setup to create threads for each
+ connection.
+ If you do use global variables and forking, you should be aware, then,
+ that these cannot be shared between associations, unless you explicitly
+ disable forking by command line parameters.
+ </para>
+
+ <para>
+ The server provides a mechanism for controlling some of its behavior
+ without using command-line options. The function
+ </para>
+
+ <synopsis>
+statserv_options_block *statserv_getcontrol(void);
+ </synopsis>
+
+ <para>
+ will return a pointer to a <literal>struct statserv_options_block</literal>
+ describing the current default settings of the server. The structure
+ contains these elements:
+
+ <variablelist>
+ <varlistentry><term>
+ <literal>int dynamic</literal></term><listitem><para>
+ A boolean value, which determines whether the server
+ will fork on each incoming request (TRUE), or not (FALSE). Default is
+ TRUE. This flag is only read by UNIX-based servers (WIN32 based servers
+ doesn't fork).
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>int threads</literal></term><listitem><para>
+ A boolean value, which determines whether the server
+ will create a thread on each incoming request (TRUE), or not (FALSE).
+ Default is FALSE. This flag is only read by UNIX-based servers
+ that offer POSIX Threads support.
+ WIN32-based servers always operate in threaded mode.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>int inetd</literal></term><listitem><para>
+ A boolean value, which determines whether the server
+ will operates under a UNIX INET daemon (inetd). Default is FALSE.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>int loglevel</literal></term><listitem><para>
+ Set this by ORing the constants defined in
+ <filename>include/yaz/yaz-log.h</filename>.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>char logfile[ODR_MAXNAME+1]</literal></term>
+ <listitem><para>File for diagnostic output ("": stderr).
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>char apdufile[ODR_MAXNAME+1]</literal></term>
+ <listitem><para>
+ Name of file for logging incoming and outgoing APDUs
+ ("": don't log APDUs, "-":
+ <literal>stderr</literal>).
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>char default_listen[1024]</literal></term>
+ <listitem><para>Same form as the command-line specification of
+ listener address. "": no default listener address.
+ Default is to listen at "tcp:@:9999". You can only
+ specify one default listener address in this fashion.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>enum oid_proto default_proto;</literal></term>
+ <listitem><para>Either <literal>PROTO_Z3950</literal> or
+ <literal>PROTO_SR</literal>.
+ Default is <literal>PROTO_Z39_50</literal>.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>int idle_timeout;</literal></term>
+ <listitem><para>Maximum session idle-time, in minutes. Zero indicates
+ no (infinite) timeout. Default is 120 minutes.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>int maxrecordsize;</literal></term>
+ <listitem><para>Maximum permissible record (message) size. Default
+ is 1Mb. This amount of memory will only be allocated if a
+ client requests a very large amount of records in one operation
+ (or a big record).
+ Set it to a lower number if you are worried about resource
+ consumption on your host system.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>char configname[ODR_MAXNAME+1]</literal></term>
+ <listitem><para>Passed to the backend when a new connection is received.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>char setuid[ODR_MAXNAME+1]</literal></term>
+ <listitem><para>Set user id to the user specified, after binding
+ the listener addresses.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>void (*bend_start)(struct statserv_options_block *p)</literal>
+ </term>
+ <listitem><para>Pointer to function which is called after the
+ command line options have been parsed - but before the server
+ starts listening.
+ For forked UNIX servers this handler is called in the mother
+ process; for threaded servers this handler is called in the
+ main thread.
+ The default value of this pointer is NULL in which case it
+ isn't invoked by the frontend server.
+ When the server operates as an NT service this handler is called
+ whenever the service is started.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>void (*bend_stop)(struct statserv_options_block *p)</literal>
+ </term>
+ <listitem><para>Pointer to function which is called whenever the server
+ has stopped listening for incoming connections. This function pointer
+ has a default value of NULL in which case it isn't called.
+ When the server operates as an NT service this handler is called
+ whenever the service is stopped.
+ </para></listitem></varlistentry>
+
+ <varlistentry><term>
+ <literal>void *handle</literal></term>
+ <listitem><para>User defined pointer (default value NULL).
+ This is a per-server handle that can be used to specify "user-data".
+ Do not confuse this with the session-handle as returned by bend_init.
+ </para></listitem></varlistentry>
+
+ </variablelist>
+ </para>
+
+ <para>
+ The pointer returned by <literal>statserv_getcontrol</literal> points to
+ a static area. You are allowed to change the contents of the structure,
+ but the changes will not take effect before you call
+ </para>
+
+ <synopsis>
+void statserv_setcontrol(statserv_options_block *block);
+ </synopsis>
+
+ <note>
+ <para>
+ that you should generally update this structure before calling
+ <function>statserv_main()</function>.
+ </para>
+ </note>
+ </sect1>
+
+ <sect1 id="server.backendfunctions"><title>The Backend Functions</title>
+
+ <para>
+ For each service of the protocol, the backend interface declares one or
+ two functions. You are required to provide implementations of the
+ functions representing the services that you wish to implement.
+ </para>
+
+ <sect2><title>Init</title>
+
+ <synopsis>
+bend_initresult (*bend_init)(bend_initrequest *r);
+ </synopsis>
+
+ <para>
+ This handler is called once for each new connection request, after
+ a new process/thread has been created, and an Initialize Request has
+ been received from the client. The pointer to the
+ <function>bend_init</function> handler is passed in the call to
+ <function>statserv_start</function>.
+ </para>
+ <para>
+ Unlike previous versions of YAZ, the <function>bend_init</function> also
+ serves as a handler that defines the Z39.50 services that the backend
+ wish to support. Pointers to <emphasis>all</emphasis> service handlers,
+ including search - and fetch must be specified here in this handler.
+ </para>
+ <para>
+ The request - and result structures are defined as
+ </para>
+
+ <synopsis>