Rename frontend.xml to server.xml
authorAdam Dickmeiss <adam@indexdata.dk>
Tue, 9 Jun 2009 07:12:23 +0000 (09:12 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 9 Jun 2009 07:12:23 +0000 (09:12 +0200)
doc/Makefile.am
doc/entities.ent
doc/frontend.xml [deleted file]
doc/server.xml [new file with mode: 0644]
doc/yaz.xml

index 44decb0..49f6a50 100644 (file)
@@ -5,7 +5,7 @@ SUBDIRS = common
 
 XMLFILES=bookinfo.xml introduction.xml installation.xml \
  indexdata.xml \
- asn.xml tools.xml odr.xml comstack.xml frontend.xml license.xml \
+ asn.xml tools.xml odr.xml comstack.xml server.xml license.xml \
  future.xml zoom.xml credits.xml gfs-options.xml \
  yaz.xml yaz-client-commands.xml soap.xml gfs-virtual.xml gfs-synopsis.xml \
  std-oid-table.xml manref.xml
index 77cd307..0c3d210 100644 (file)
@@ -8,7 +8,7 @@
 <!ENTITY chap-tools SYSTEM "tools.xml">
 <!ENTITY chap-odr SYSTEM "odr.xml">
 <!ENTITY chap-comstack SYSTEM "comstack.xml">
-<!ENTITY chap-frontend SYSTEM "frontend.xml">
+<!ENTITY chap-server SYSTEM "server.xml">
 <!ENTITY chap-future SYSTEM "future.xml">
 <!ENTITY std-oid-table SYSTEM "std-oid-table.xml">
 <!ENTITY app-license SYSTEM "license.xml">
diff --git a/doc/frontend.xml b/doc/frontend.xml
deleted file mode 100644 (file)
index 18a4f27..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
- <chapter id="server"><title>Generic server</title>
-  <sect1 id="server.introduction"><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 or SRU, &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>
-
-   <note>
-    <para>
-     The &yaz; server does not support XCQL.
-     </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>
-    
-    <listitem><para>
-      Return Explain for SRU (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>char logfile[ODR_MAXNAME+1]</literal></term>
-      <listitem><para>File for diagnostic output (&quot;&quot;: 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
-       (&quot;&quot;: don't log APDUs, &quot;-&quot;:
-       <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. &quot;&quot;: no default listener address.
-       Default is to listen at &quot;tcp:@:9999&quot;. 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 15 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 id="server.init"><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>
-     This handler is also called when operating in SRU mode - when
-     a connection has been made (even though SRU does not offer
-     this service).
-    </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>
-typedef struct bend_initrequest
-{
-    /** \brief user/name/password to be read */
-    Z_IdAuthentication *auth; 
-    /** \brief encoding stream (for results) */
-    ODR stream;
-    /** \brief printing stream */
-    ODR print;
-    /** \brief decoding stream (use stream for results) */
-    ODR decode; 
-    /** \brief reference ID */
-    Z_ReferenceId *referenceId;
-    /** \brief peer address of client */
-    char *peer_name;           
-    
-    /** \brief character set and language negotiation 
-
-    see include/yaz/z-charneg.h 
-    */
-    Z_CharSetandLanguageNegotiation *charneg_request;
-
-    /** \brief character negotiation response */
-    Z_External *charneg_response;
-
-    /** \brief character set (encoding) for query terms 
-        
-    This is NULL by default. It should be set to the native character
-    set that the backend assumes for query terms */
-    char *query_charset;      
-
-    /** \brief whehter query_charset also applies to recors 
-    
-    Is 0 (No) by default. Set to 1 (yes) if records is in the same
-    character set as queries. If in doubt, use 0 (No).
-    */
-    int records_in_same_charset;
-
-    char *implementation_id;
-    char *implementation_name;
-    char *implementation_version;
-
-    /** \brief Z39.50 sort handler */
-    int (*bend_sort)(void *handle, bend_sort_rr *rr);
-    /** \brief SRU/Z39.50 search handler */
-    int (*bend_search)(void *handle, bend_search_rr *rr);
-    /** \brief SRU/Z39.50 fetch handler */
-    int (*bend_fetch)(void *handle, bend_fetch_rr *rr);
-    /** \brief SRU/Z39.50 present handler */
-    int (*bend_present)(void *handle, bend_present_rr *rr);
-    /** \brief Z39.50 extended services handler */
-    int (*bend_esrequest) (void *handle, bend_esrequest_rr *rr);
-    /** \brief Z39.50 delete result set handler */
-    int (*bend_delete)(void *handle, bend_delete_rr *rr);
-    /** \brief Z39.50 scan handler */
-    int (*bend_scan)(void *handle, bend_scan_rr *rr);
-    /** \brief Z39.50 segment facility handler */
-    int (*bend_segment)(void *handle, bend_segment_rr *rr);
-    /** \brief SRU explain handler */
-    int (*bend_explain)(void *handle, bend_explain_rr *rr);
-    /** \brief SRU scan handler */
-    int (*bend_srw_scan)(void *handle, bend_scan_rr *rr);
-    /** \brief SRU record update handler */
-    int (*bend_srw_update)(void *handle, bend_update_rr *rr);
-
-    /** \brief whether named result sets are supported (0=disable, 1=enable) */
-    int named_result_sets;
-} bend_initrequest;
-
-typedef struct bend_initresult
-{
-    int errcode;               /* 0==OK */
-    char *errstring;           /* system error string or NULL */
-    void *handle;              /* private handle to the backend module */
-} bend_initresult;
-    </synopsis>
-
-    <para>
-     In general, the server frontend expects that the
-     <literal>bend_*result</literal> pointer that you return is valid at
-     least until the next call to a <literal>bend_* function</literal>.
-     This applies to all of the functions described herein. The parameter
-     structure passed to you in the call belongs to the server frontend, and
-     you should not make assumptions about its contents after the current
-     function call has completed. In other words, if you want to retain any
-     of the contents of a request structure, you should copy them.
-    </para>
-
-    <para>
-     The <literal>errcode</literal> should be zero if the initialization of
-     the backend went well. Any other value will be interpreted as an error.
-     The <literal>errstring</literal> isn't used in the current version, but
-     one option would be to stick it in the initResponse as a VisibleString.
-     The <literal>handle</literal> is the most important parameter. It should
-     be set to some value that uniquely identifies the current session to
-     the backend implementation. It is used by the frontend server in any
-     future calls to a backend function.
-     The typical use is to set it to point to a dynamically allocated state
-     structure that is private to your backend module.
-    </para>
-
-    <para>
-     The <literal>auth</literal> member holds the authentication information
-     part of the Z39.50 Initialize Request. Interpret this if your serves
-     requires authentication. 
-    </para>
-
-    <para>
-     The members <literal>peer_name</literal>,
-     <literal>implementation_id</literal>,
-     <literal>implementation_name</literal> and
-     <literal>implementation_version</literal> holds
-     DNS of client, ID of implementor, name
-     of client (Z39.50) implementation - and version.
-    </para>
-
-    <para>
-     The <literal>bend_</literal> - members are set to NULL when
-     <function>bend_init</function> is called. Modify the pointers by
-     setting them to point to backend functions.
-    </para>
-
-   </sect2>
-
-   <sect2 id="server.search.retrieve"><title>Search and Retrieve</title>
-
-    <para>We now describe the handlers that are required to support search -
-     and retrieve. You must support two functions - one for search - and one
-     for fetch (retrieval of one record). If desirable you can provide a
-     third handler which is called when a present request is received which
-     allows you to optimize retrieval of multiple-records.
-    </para>
-
-    <synopsis>
-int (*bend_search) (void *handle, bend_search_rr *rr);
-
-typedef struct {
-    char *setname;             /* name to give to this set */
-    int replace_set;           /* replace set, if it already exists */
-    int num_bases;             /* number of databases in list */
-    char **basenames;          /* databases to search */
-    Z_ReferenceId *referenceId;/* reference ID */
-    Z_Query *query;            /* query structure */
-    ODR stream;                /* encode stream */
-    ODR decode;                /* decode stream */
-    ODR print;                 /* print stream */
-
-    bend_request request;
-    bend_association association;
-    int *fd;
-    int hits;                  /* number of hits */
-    int errcode;               /* 0==OK */
-    char *errstring;           /* system error string or NULL */
-    Z_OtherInformation *search_info; /* additional search info */
-    char *srw_sortKeys;        /* holds SRU/SRW sortKeys info */
-    char *srw_setname;         /* holds SRU/SRW generated resultsetID */
-    int *srw_setnameIdleTime;  /* holds SRU/SRW life-time */
-    int estimated_hit_count;   /* if hit count is estimated */
-    int partial_resultset;     /* if result set is partial */
-} bend_search_rr;
-    </synopsis>
-
-    <para>
-     The <function>bend_search</function> handler is a fairly close
-     approximation of a protocol Z39.50 Search Request - and Response PDUs
-     The <literal>setname</literal> is the resultSetName from the protocol.
-     You are required to establish a mapping between the set name and whatever
-     your backend database likes to use.
-     Similarly, the <literal>replace_set</literal> is a boolean value
-     corresponding to the resultSetIndicator field in the protocol.
-     <literal>num_bases/basenames</literal> is a length of/array of character
-     pointers to the database names provided by the client.
-     The <literal>query</literal> is the full query structure as defined in
-     the protocol ASN.1 specification.
-     It can be either of the possible query types, and it's up to you to
-     determine if you can handle the provided query type.
-     Rather than reproduce the C interface here, we'll refer you to the
-     structure definitions in the file
-     <filename>include/yaz/z-core.h</filename>. If you want to look at the
-     attributeSetId OID of the RPN query, you can either match it against
-     your own internal tables, or you can use the <link linkend="tools.oid">
-     OID tools</link>.
-    </para>
-
-    <para>
-     The structure contains a number of hits, and an
-     <literal>errcode/errstring</literal> pair. If an error occurs
-     during the search, or if you're unhappy with the request, you should
-     set the errcode to a value from the BIB-1 diagnostic set. The value
-     will then be returned to the user in a nonsurrogate diagnostic record
-     in the response. The <literal>errstring</literal>, if provided, will
-     go in the addinfo field. Look at the protocol definition for the
-     defined error codes, and the suggested uses of the addinfo field.
-    </para>
-
-    <para>
-     The <function>bend_search</function> handler is also called when
-     the frontend server receives a SRU SearchRetrieveRequest.
-     For SRU, a CQL query is usually provided by the client.
-     The CQL query is available as part of <literal>Z_Query</literal>
-     structure (note that CQL is now part of Z39.50 via an external).
-     To support CQL in existing implementations that only do Type-1,
-     we refer to the CQL-to-PQF tool described
-     <link linkend="cql.to.pqf">here</link>.
-    </para>
-
-    <para>
-     To maintain backwards compatibility, the frontend server
-     of yaz always assume that error codes are BIB-1 diagnostics.
-     For SRU operation, a Bib-1 diagnostic code is mapped to
-     SRU diagnostic.
-    </para>
-    
-    <synopsis>
-int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
-
-typedef struct bend_fetch_rr {
-    char *setname;             /* set name */
-    int number;                /* record number */
-    Z_ReferenceId *referenceId;/* reference ID */
-    Odr_oid *request_format;        /* format, transfer syntax (OID) */
-    Z_RecordComposition *comp; /* Formatting instructions */
-    ODR stream;                /* encoding stream - memory source if req */
-    ODR print;                 /* printing stream */
-
-    char *basename;            /* name of database that provided record */
-    int len;                   /* length of record or -1 if structured */
-    char *record;              /* record */
-    int last_in_set;           /* is it?  */
-    Odr_oid *output_format;        /* response format/syntax (OID) */
-    int errcode;               /* 0==success */
-    char *errstring;           /* system error string or NULL */
-    int surrogate_flag;        /* surrogate diagnostic */
-    char *schema;              /* string record schema input/output */
-} bend_fetch_rr;
-    </synopsis>
-
-    <para>
-     The frontend server calls the <function>bend_fetch</function> handler
-     when it needs database records to fulfill a Z39.50 Search Request, a
-     Z39.50 Present Request or a SRU SearchRetrieveRequest.
-     The <literal>setname</literal> is simply the name of the result set
-     that holds the reference to the desired record.
-     The <literal>number</literal> is the offset into the set (with 1
-     being the first record in the set). The <literal>format</literal> field
-     is the record format requested by the client (See
-     <xref linkend="tools.oid"/>).
-     A value of NULL for <literal>format</literal> indicates that the
-     client did not request a specific format.
-     The <literal>stream</literal> argument is an &odr; stream which
-     should be used for allocating space for structured data records.
-     The stream will be reset when all records have been assembled, and
-     the response package has been transmitted.
-     For unstructured data, the backend is responsible for maintaining a
-     static or dynamic buffer for the record between calls.
-    </para>
-
-    <para>
-     If a SRU SearchRetrieveRequest is received by the frontend server,
-     the <literal>referenceId</literal> is NULL and the
-     <literal>format</literal> (transfer syntax) is the OID for XML.
-     The schema for SRU is stored in both the
-     <literal>Z_RecordComposition</literal>
-     structure and <literal>schema</literal> (simple string).
-    </para>
-
-    <para>
-     In the structure, the <literal>basename</literal> is the name of the
-     database that holds the
-     record. <literal>len</literal> is the length of the record returned, in
-     bytes, and <literal>record</literal> is a pointer to the record.
-     <literal>last_in_set</literal> should be nonzero only if the record
-     returned is the last one in the given result set.
-     <literal>errcode</literal> and <literal>errstring</literal>, if
-     given, will be interpreted as a global error pertaining to the
-     set, and will be returned in a non-surrogate-diagnostic.
-     If you wish to return the error as a surrogate-diagnostic
-     (local error) you can do this by setting
-     <literal>surrogate_flag</literal> to 1 also.
-    </para>
-
-    <para>
-     If the <literal>len</literal> field has the value -1, then
-     <literal>record</literal> is assumed to point to a constructed data
-     type. The <literal>format</literal> field will be used to determine
-     which encoder should be used to serialize the data.
-    </para>
-
-    <note>
-     <para>
-      If your backend generates structured records, it should use
-      <function>odr_malloc()</function> on the provided stream for allocating
-      data: This allows the frontend server to keep track of the record sizes.
-     </para>
-    </note>
-
-    <para>
-     The <literal>format</literal> field is mapped to an object identifier
-     in the direct reference of the resulting EXTERNAL representation
-     of the record.
-    </para>
-
-    <note>
-     <para>
-      The current version of &yaz; only supports the direct reference mode.
-     </para>
-    </note>
-
-    <synopsis>
-int (*bend_present) (void *handle, bend_present_rr *rr);
-
-typedef struct {
-    char *setname;             /* set name */
-    int start;
-    int number;                /* record number */
-    Odr_oid *format;           /* format, transfer syntax (OID) */
-    Z_ReferenceId *referenceId;/* reference ID */
-    Z_RecordComposition *comp; /* Formatting instructions */
-    ODR stream;                /* encoding stream - memory source if required */
-    ODR print;                 /* printing stream */
-    bend_request request;
-    bend_association association;
-
-    int hits;                  /* number of hits */
-    int errcode;               /* 0==OK */
-    char *errstring;           /* system error string or NULL */
-} bend_present_rr;
-    </synopsis>
-
-    <para>
-     The <function>bend_present</function> handler is called when
-     the server receives a Z39.50 Present Request.
-     The <literal>setname</literal>,
-     <literal>start</literal> and <literal>number</literal> is the
-     name of the result set - start position - and number of records to
-     be retrieved respectively. <literal>format</literal> and
-     <literal>comp</literal> is the preferred transfer syntax and element
-     specifications of the present request.
-    </para>
-    <para>
-     Note that this is handler serves as a supplement for
-     <function>bend_fetch</function> and need not to be defined in order to
-     support search - and retrieve. 
-    </para>
-
-   </sect2>
-
-   <sect2 id="server.delete"><title>Delete</title>
-
-    <para>
-     For back-ends that supports delete of a result set only one handler
-     must be defined.
-    </para>
-
-    <synopsis>
-int (*bend_delete)(void *handle, bend_delete_rr *rr);
-
-typedef struct bend_delete_rr {
-    int function;
-    int num_setnames;
-    char **setnames;
-    Z_ReferenceId *referenceId;
-    int delete_status;      /* status for the whole operation */
-    int *statuses;          /* status each set - indexed as setnames */
-    ODR stream;
-    ODR print; 
-} bend_delete_rr;
-    </synopsis>
-
-    <note>
-     <para>
-      The delete set function definition is rather primitive, mostly because
-      we have had no practical need for it as of yet. If someone wants
-      to provide a full delete service, we'd be happy to add the
-      extra parameters that are required. Are there clients out there
-      that will actually delete sets they no longer need?
-     </para>
-    </note>
-
-   </sect2>
-
-   <sect2 id="server.scan"><title>Scan</title>
-
-    <para>
-     For servers that wish to offer the scan service one handler
-     must be defined.
-    </para>
-
-    <synopsis>
-int (*bend_scan)(void *handle, bend_scan_rr *rr);
-
-typedef enum {
-    BEND_SCAN_SUCCESS,  /* ok */
-    BEND_SCAN_PARTIAL   /* not all entries could be found */
-} bend_scan_status;
-
-typedef struct bend_scan_rr {
-    int num_bases;      /* number of elements in databaselist */
-    char **basenames;   /* databases to search */
-    Odr_oid *attributeset;
-    Z_ReferenceId *referenceId; /* reference ID */
-    Z_AttributesPlusTerm *term;
-    ODR stream;         /* encoding stream - memory source if required */
-    ODR print;          /* printing stream */
-
-    int *step_size;     /* step size */
-    int term_position;  /* desired index of term in result list/returned */
-    int num_entries;    /* number of entries requested/returned */
-
-    /* scan term entries. The called handler does not have
-       to allocate this. Size of entries is num_entries (see above) */
-    struct scan_entry *entries;
-    bend_scan_status status;
-    int errcode;
-    char *errstring;
-    char *scanClause;   /* CQL scan clause */
-    char *setname;      /* Scan in result set (NULL if omitted) */
-} bend_scan_rr;
-    </synopsis>
-   <para>
-    This backend server handles both Z39.50 scan 
-    and SRU scan. In order for a handler to distinguish between SRU (CQL) scan 
-    Z39.50 Scan , it must check for a non-NULL value of 
-    <literal>scanClause</literal>.
-   </para>
-   <note>
-    <para>
-     if designed today, it would be a choice using a union or similar,
-     but that would break binary compatibility with existing servers.
-    </para>
-    </note>
-   </sect2>
-  </sect1>
-
-  <sect1 id="server.invocation"><title>Application Invocation</title>
-
-   <para>
-    The finished application has the following
-    invocation syntax (by way of <function>statserv_main()</function>):
-   </para>
-
-   &gfs-synopsis;
-   
-   <para>
-    The options are:
-
-    &gfs-options;
-
-   </para>
-   
-   <para>
-    A listener specification consists of a transport mode followed by a
-    colon (:) followed by a listener address. The transport mode is
-    either <literal>tcp</literal>, <literal>unix:</literal> or
-    <literal>ssl</literal>.
-   </para>
-   
-   <para>
-    For TCP and SSL, an address has the form
-   </para>
-
-   <synopsis>
-    hostname | IP-number [: portnumber]
-   </synopsis>
-   
-   <para>
-    The port number defaults to 210 (standard Z39.50 port).
-   </para>
-
-   <para>
-    For UNIX, the address is the filename of socket.
-   </para>
-
-   <para>
-    For TCP/IP and SSL, the special hostname <literal>@</literal> 
-    (at sign) is mapped to the address <literal>INADDR_ANY</literal>,
-    which causes the server to listen on any local interface. 
-   </para>
-
-   <example id="server.example.running.unix"><title>Running the GFS on Unix</title>
-    <para>
-     Assuming the server application <replaceable>appname</replaceable> is
-     started as root, the following will make it listen on port 210.
-     The server will change identity to <literal>nobody</literal>
-     and write its log to <filename>/var/log/app.log</filename>.
-     <screen>
-      application -l /var/log/app.log -u nobody tcp:@:210
-     </screen>
-    </para>
-    <para>
-     The server will accept Z39.50 requests and offer SRU service on port 210.
-    </para>
-   </example>
-   <example id="server.example.apache.sru"><title>Setting up Apache as SRU Frontend</title>
-    <para>
-     If you use <ulink url="&url.apache;">Apache</ulink>
-     as your public web server and want to offer HTTP port 80
-     access to the YAZ server on 210, you can use the
-     <ulink url="&url.apache.directive.proxypass;">
-      <literal>ProxyPass</literal></ulink> 
-     directive.
-     If you have virtual host
-     <literal>srw.mydomain</literal> you can use the following directives
-     in Apache's httpd.conf:
-     <screen>
-      &lt;VirtualHost *>
-       ErrorLog /home/srw/logs/error_log
-       TransferLog /home/srw/logs/access_log
-       ProxyPass / http://srw.mydomain:210/
-      &lt;/VirtualHost>
-     </screen>
-    </para>
-    <para>
-     The above for the Apache 1.3 series.
-    </para>
-   </example>
-   <example id="server.example.local.access">
-    <title>Running a server with local access only</title>
-    <para>
-     Servers that is only being accessed from the local host should listen
-     on UNIX file socket rather than a Internet socket. To listen on
-     <filename>/tmp/mysocket</filename> start the server as follows:
-     <screen>
-      application unix:/tmp/mysocket
-     </screen>
-    </para>
-   </example>
-  </sect1>
-  <sect1 id="server.vhosts"><title>GFS Configuration and Virtual Hosts</title>
-   &gfs-virtual;
-  </sect1>
- </chapter>
- <!-- Keep this comment at the end of the file
- Local variables:
- mode: sgml
- sgml-omittag:t
- sgml-shorttag:t
- sgml-minimize-attributes:nil
- sgml-always-quote-attributes:t
- sgml-indent-step:1
- sgml-indent-data:t
- sgml-parent-document: "yaz.xml"
- sgml-local-catalogs: nil
- sgml-namecase-general:t
- End:
- -->
diff --git a/doc/server.xml b/doc/server.xml
new file mode 100644 (file)
index 0000000..18a4f27
--- /dev/null
@@ -0,0 +1,893 @@
+ <chapter id="server"><title>Generic server</title>
+  <sect1 id="server.introduction"><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 or SRU, &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>
+
+   <note>
+    <para>
+     The &yaz; server does not support XCQL.
+     </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>
+    
+    <listitem><para>
+      Return Explain for SRU (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>char logfile[ODR_MAXNAME+1]</literal></term>
+      <listitem><para>File for diagnostic output (&quot;&quot;: 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
+       (&quot;&quot;: don't log APDUs, &quot;-&quot;:
+       <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. &quot;&quot;: no default listener address.
+       Default is to listen at &quot;tcp:@:9999&quot;. 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 15 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 id="server.init"><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>
+     This handler is also called when operating in SRU mode - when
+     a connection has been made (even though SRU does not offer
+     this service).
+    </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>
+typedef struct bend_initrequest
+{
+    /** \brief user/name/password to be read */
+    Z_IdAuthentication *auth; 
+    /** \brief encoding stream (for results) */
+    ODR stream;
+    /** \brief printing stream */
+    ODR print;
+    /** \brief decoding stream (use stream for results) */
+    ODR decode; 
+    /** \brief reference ID */
+    Z_ReferenceId *referenceId;
+    /** \brief peer address of client */
+    char *peer_name;           
+    
+    /** \brief character set and language negotiation 
+
+    see include/yaz/z-charneg.h 
+    */
+    Z_CharSetandLanguageNegotiation *charneg_request;
+
+    /** \brief character negotiation response */
+    Z_External *charneg_response;
+
+    /** \brief character set (encoding) for query terms 
+        
+    This is NULL by default. It should be set to the native character
+    set that the backend assumes for query terms */
+    char *query_charset;      
+
+    /** \brief whehter query_charset also applies to recors 
+    
+    Is 0 (No) by default. Set to 1 (yes) if records is in the same
+    character set as queries. If in doubt, use 0 (No).
+    */
+    int records_in_same_charset;
+
+    char *implementation_id;
+    char *implementation_name;
+    char *implementation_version;
+
+    /** \brief Z39.50 sort handler */
+    int (*bend_sort)(void *handle, bend_sort_rr *rr);
+    /** \brief SRU/Z39.50 search handler */
+    int (*bend_search)(void *handle, bend_search_rr *rr);
+    /** \brief SRU/Z39.50 fetch handler */
+    int (*bend_fetch)(void *handle, bend_fetch_rr *rr);
+    /** \brief SRU/Z39.50 present handler */
+    int (*bend_present)(void *handle, bend_present_rr *rr);
+    /** \brief Z39.50 extended services handler */
+    int (*bend_esrequest) (void *handle, bend_esrequest_rr *rr);
+    /** \brief Z39.50 delete result set handler */
+    int (*bend_delete)(void *handle, bend_delete_rr *rr);
+    /** \brief Z39.50 scan handler */
+    int (*bend_scan)(void *handle, bend_scan_rr *rr);
+    /** \brief Z39.50 segment facility handler */
+    int (*bend_segment)(void *handle, bend_segment_rr *rr);
+    /** \brief SRU explain handler */
+    int (*bend_explain)(void *handle, bend_explain_rr *rr);
+    /** \brief SRU scan handler */
+    int (*bend_srw_scan)(void *handle, bend_scan_rr *rr);
+    /** \brief SRU record update handler */
+    int (*bend_srw_update)(void *handle, bend_update_rr *rr);
+
+    /** \brief whether named result sets are supported (0=disable, 1=enable) */
+    int named_result_sets;
+} bend_initrequest;
+
+typedef struct bend_initresult
+{
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+    void *handle;              /* private handle to the backend module */
+} bend_initresult;
+    </synopsis>
+
+    <para>
+     In general, the server frontend expects that the
+     <literal>bend_*result</literal> pointer that you return is valid at
+     least until the next call to a <literal>bend_* function</literal>.
+     This applies to all of the functions described herein. The parameter
+     structure passed to you in the call belongs to the server frontend, and
+     you should not make assumptions about its contents after the current
+     function call has completed. In other words, if you want to retain any
+     of the contents of a request structure, you should copy them.
+    </para>
+
+    <para>
+     The <literal>errcode</literal> should be zero if the initialization of
+     the backend went well. Any other value will be interpreted as an error.
+     The <literal>errstring</literal> isn't used in the current version, but
+     one option would be to stick it in the initResponse as a VisibleString.
+     The <literal>handle</literal> is the most important parameter. It should
+     be set to some value that uniquely identifies the current session to
+     the backend implementation. It is used by the frontend server in any
+     future calls to a backend function.
+     The typical use is to set it to point to a dynamically allocated state
+     structure that is private to your backend module.
+    </para>
+
+    <para>
+     The <literal>auth</literal> member holds the authentication information
+     part of the Z39.50 Initialize Request. Interpret this if your serves
+     requires authentication. 
+    </para>
+
+    <para>
+     The members <literal>peer_name</literal>,
+     <literal>implementation_id</literal>,
+     <literal>implementation_name</literal> and
+     <literal>implementation_version</literal> holds
+     DNS of client, ID of implementor, name
+     of client (Z39.50) implementation - and version.
+    </para>
+
+    <para>
+     The <literal>bend_</literal> - members are set to NULL when
+     <function>bend_init</function> is called. Modify the pointers by
+     setting them to point to backend functions.
+    </para>
+
+   </sect2>
+
+   <sect2 id="server.search.retrieve"><title>Search and Retrieve</title>
+
+    <para>We now describe the handlers that are required to support search -
+     and retrieve. You must support two functions - one for search - and one
+     for fetch (retrieval of one record). If desirable you can provide a
+     third handler which is called when a present request is received which
+     allows you to optimize retrieval of multiple-records.
+    </para>
+
+    <synopsis>
+int (*bend_search) (void *handle, bend_search_rr *rr);
+
+typedef struct {
+    char *setname;             /* name to give to this set */
+    int replace_set;           /* replace set, if it already exists */
+    int num_bases;             /* number of databases in list */
+    char **basenames;          /* databases to search */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Z_Query *query;            /* query structure */
+    ODR stream;                /* encode stream */
+    ODR decode;                /* decode stream */
+    ODR print;                 /* print stream */
+
+    bend_request request;
+    bend_association association;
+    int *fd;
+    int hits;                  /* number of hits */
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+    Z_OtherInformation *search_info; /* additional search info */
+    char *srw_sortKeys;        /* holds SRU/SRW sortKeys info */
+    char *srw_setname;         /* holds SRU/SRW generated resultsetID */
+    int *srw_setnameIdleTime;  /* holds SRU/SRW life-time */
+    int estimated_hit_count;   /* if hit count is estimated */
+    int partial_resultset;     /* if result set is partial */
+} bend_search_rr;
+    </synopsis>
+
+    <para>
+     The <function>bend_search</function> handler is a fairly close
+     approximation of a protocol Z39.50 Search Request - and Response PDUs
+     The <literal>setname</literal> is the resultSetName from the protocol.
+     You are required to establish a mapping between the set name and whatever
+     your backend database likes to use.
+     Similarly, the <literal>replace_set</literal> is a boolean value
+     corresponding to the resultSetIndicator field in the protocol.
+     <literal>num_bases/basenames</literal> is a length of/array of character
+     pointers to the database names provided by the client.
+     The <literal>query</literal> is the full query structure as defined in
+     the protocol ASN.1 specification.
+     It can be either of the possible query types, and it's up to you to
+     determine if you can handle the provided query type.
+     Rather than reproduce the C interface here, we'll refer you to the
+     structure definitions in the file
+     <filename>include/yaz/z-core.h</filename>. If you want to look at the
+     attributeSetId OID of the RPN query, you can either match it against
+     your own internal tables, or you can use the <link linkend="tools.oid">
+     OID tools</link>.
+    </para>
+
+    <para>
+     The structure contains a number of hits, and an
+     <literal>errcode/errstring</literal> pair. If an error occurs
+     during the search, or if you're unhappy with the request, you should
+     set the errcode to a value from the BIB-1 diagnostic set. The value
+     will then be returned to the user in a nonsurrogate diagnostic record
+     in the response. The <literal>errstring</literal>, if provided, will
+     go in the addinfo field. Look at the protocol definition for the
+     defined error codes, and the suggested uses of the addinfo field.
+    </para>
+
+    <para>
+     The <function>bend_search</function> handler is also called when
+     the frontend server receives a SRU SearchRetrieveRequest.
+     For SRU, a CQL query is usually provided by the client.
+     The CQL query is available as part of <literal>Z_Query</literal>
+     structure (note that CQL is now part of Z39.50 via an external).
+     To support CQL in existing implementations that only do Type-1,
+     we refer to the CQL-to-PQF tool described
+     <link linkend="cql.to.pqf">here</link>.
+    </para>
+
+    <para>
+     To maintain backwards compatibility, the frontend server
+     of yaz always assume that error codes are BIB-1 diagnostics.
+     For SRU operation, a Bib-1 diagnostic code is mapped to
+     SRU diagnostic.
+    </para>
+    
+    <synopsis>
+int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
+
+typedef struct bend_fetch_rr {
+    char *setname;             /* set name */
+    int number;                /* record number */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Odr_oid *request_format;        /* format, transfer syntax (OID) */
+    Z_RecordComposition *comp; /* Formatting instructions */
+    ODR stream;                /* encoding stream - memory source if req */
+    ODR print;                 /* printing stream */
+
+    char *basename;            /* name of database that provided record */
+    int len;                   /* length of record or -1 if structured */
+    char *record;              /* record */
+    int last_in_set;           /* is it?  */
+    Odr_oid *output_format;        /* response format/syntax (OID) */
+    int errcode;               /* 0==success */
+    char *errstring;           /* system error string or NULL */
+    int surrogate_flag;        /* surrogate diagnostic */
+    char *schema;              /* string record schema input/output */
+} bend_fetch_rr;
+    </synopsis>
+
+    <para>
+     The frontend server calls the <function>bend_fetch</function> handler
+     when it needs database records to fulfill a Z39.50 Search Request, a
+     Z39.50 Present Request or a SRU SearchRetrieveRequest.
+     The <literal>setname</literal> is simply the name of the result set
+     that holds the reference to the desired record.
+     The <literal>number</literal> is the offset into the set (with 1
+     being the first record in the set). The <literal>format</literal> field
+     is the record format requested by the client (See
+     <xref linkend="tools.oid"/>).
+     A value of NULL for <literal>format</literal> indicates that the
+     client did not request a specific format.
+     The <literal>stream</literal> argument is an &odr; stream which
+     should be used for allocating space for structured data records.
+     The stream will be reset when all records have been assembled, and
+     the response package has been transmitted.
+     For unstructured data, the backend is responsible for maintaining a
+     static or dynamic buffer for the record between calls.
+    </para>
+
+    <para>
+     If a SRU SearchRetrieveRequest is received by the frontend server,
+     the <literal>referenceId</literal> is NULL and the
+     <literal>format</literal> (transfer syntax) is the OID for XML.
+     The schema for SRU is stored in both the
+     <literal>Z_RecordComposition</literal>
+     structure and <literal>schema</literal> (simple string).
+    </para>
+
+    <para>
+     In the structure, the <literal>basename</literal> is the name of the
+     database that holds the
+     record. <literal>len</literal> is the length of the record returned, in
+     bytes, and <literal>record</literal> is a pointer to the record.
+     <literal>last_in_set</literal> should be nonzero only if the record
+     returned is the last one in the given result set.
+     <literal>errcode</literal> and <literal>errstring</literal>, if
+     given, will be interpreted as a global error pertaining to the
+     set, and will be returned in a non-surrogate-diagnostic.
+     If you wish to return the error as a surrogate-diagnostic
+     (local error) you can do this by setting
+     <literal>surrogate_flag</literal> to 1 also.
+    </para>
+
+    <para>
+     If the <literal>len</literal> field has the value -1, then
+     <literal>record</literal> is assumed to point to a constructed data
+     type. The <literal>format</literal> field will be used to determine
+     which encoder should be used to serialize the data.
+    </para>
+
+    <note>
+     <para>
+      If your backend generates structured records, it should use
+      <function>odr_malloc()</function> on the provided stream for allocating
+      data: This allows the frontend server to keep track of the record sizes.
+     </para>
+    </note>
+
+    <para>
+     The <literal>format</literal> field is mapped to an object identifier
+     in the direct reference of the resulting EXTERNAL representation
+     of the record.
+    </para>
+
+    <note>
+     <para>
+      The current version of &yaz; only supports the direct reference mode.
+     </para>
+    </note>
+
+    <synopsis>
+int (*bend_present) (void *handle, bend_present_rr *rr);
+
+typedef struct {
+    char *setname;             /* set name */
+    int start;
+    int number;                /* record number */
+    Odr_oid *format;           /* format, transfer syntax (OID) */
+    Z_ReferenceId *referenceId;/* reference ID */
+    Z_RecordComposition *comp; /* Formatting instructions */
+    ODR stream;                /* encoding stream - memory source if required */
+    ODR print;                 /* printing stream */
+    bend_request request;
+    bend_association association;
+
+    int hits;                  /* number of hits */
+    int errcode;               /* 0==OK */
+    char *errstring;           /* system error string or NULL */
+} bend_present_rr;
+    </synopsis>
+
+    <para>
+     The <function>bend_present</function> handler is called when
+     the server receives a Z39.50 Present Request.
+     The <literal>setname</literal>,
+     <literal>start</literal> and <literal>number</literal> is the
+     name of the result set - start position - and number of records to
+     be retrieved respectively. <literal>format</literal> and
+     <literal>comp</literal> is the preferred transfer syntax and element
+     specifications of the present request.
+    </para>
+    <para>
+     Note that this is handler serves as a supplement for
+     <function>bend_fetch</function> and need not to be defined in order to
+     support search - and retrieve. 
+    </para>
+
+   </sect2>
+
+   <sect2 id="server.delete"><title>Delete</title>
+
+    <para>
+     For back-ends that supports delete of a result set only one handler
+     must be defined.
+    </para>
+
+    <synopsis>
+int (*bend_delete)(void *handle, bend_delete_rr *rr);
+
+typedef struct bend_delete_rr {
+    int function;
+    int num_setnames;
+    char **setnames;
+    Z_ReferenceId *referenceId;
+    int delete_status;      /* status for the whole operation */
+    int *statuses;          /* status each set - indexed as setnames */
+    ODR stream;
+    ODR print; 
+} bend_delete_rr;
+    </synopsis>
+
+    <note>
+     <para>
+      The delete set function definition is rather primitive, mostly because
+      we have had no practical need for it as of yet. If someone wants
+      to provide a full delete service, we'd be happy to add the
+      extra parameters that are required. Are there clients out there
+      that will actually delete sets they no longer need?
+     </para>
+    </note>
+
+   </sect2>
+
+   <sect2 id="server.scan"><title>Scan</title>
+
+    <para>
+     For servers that wish to offer the scan service one handler
+     must be defined.
+    </para>
+
+    <synopsis>
+int (*bend_scan)(void *handle, bend_scan_rr *rr);
+
+typedef enum {
+    BEND_SCAN_SUCCESS,  /* ok */
+    BEND_SCAN_PARTIAL   /* not all entries could be found */
+} bend_scan_status;
+
+typedef struct bend_scan_rr {
+    int num_bases;      /* number of elements in databaselist */
+    char **basenames;   /* databases to search */
+    Odr_oid *attributeset;
+    Z_ReferenceId *referenceId; /* reference ID */
+    Z_AttributesPlusTerm *term;
+    ODR stream;         /* encoding stream - memory source if required */
+    ODR print;          /* printing stream */
+
+    int *step_size;     /* step size */
+    int term_position;  /* desired index of term in result list/returned */
+    int num_entries;    /* number of entries requested/returned */
+
+    /* scan term entries. The called handler does not have
+       to allocate this. Size of entries is num_entries (see above) */
+    struct scan_entry *entries;
+    bend_scan_status status;
+    int errcode;
+    char *errstring;
+    char *scanClause;   /* CQL scan clause */
+    char *setname;      /* Scan in result set (NULL if omitted) */
+} bend_scan_rr;
+    </synopsis>
+   <para>
+    This backend server handles both Z39.50 scan 
+    and SRU scan. In order for a handler to distinguish between SRU (CQL) scan 
+    Z39.50 Scan , it must check for a non-NULL value of 
+    <literal>scanClause</literal>.
+   </para>
+   <note>
+    <para>
+     if designed today, it would be a choice using a union or similar,
+     but that would break binary compatibility with existing servers.
+    </para>
+    </note>
+   </sect2>
+  </sect1>
+
+  <sect1 id="server.invocation"><title>Application Invocation</title>
+
+   <para>
+    The finished application has the following
+    invocation syntax (by way of <function>statserv_main()</function>):
+   </para>
+
+   &gfs-synopsis;
+   
+   <para>
+    The options are:
+
+    &gfs-options;
+
+   </para>
+   
+   <para>
+    A listener specification consists of a transport mode followed by a
+    colon (:) followed by a listener address. The transport mode is
+    either <literal>tcp</literal>, <literal>unix:</literal> or
+    <literal>ssl</literal>.
+   </para>
+   
+   <para>
+    For TCP and SSL, an address has the form
+   </para>
+
+   <synopsis>
+    hostname | IP-number [: portnumber]
+   </synopsis>
+   
+   <para>
+    The port number defaults to 210 (standard Z39.50 port).
+   </para>
+
+   <para>
+    For UNIX, the address is the filename of socket.
+   </para>
+
+   <para>
+    For TCP/IP and SSL, the special hostname <literal>@</literal> 
+    (at sign) is mapped to the address <literal>INADDR_ANY</literal>,
+    which causes the server to listen on any local interface. 
+   </para>
+
+   <example id="server.example.running.unix"><title>Running the GFS on Unix</title>
+    <para>
+     Assuming the server application <replaceable>appname</replaceable> is
+     started as root, the following will make it listen on port 210.
+     The server will change identity to <literal>nobody</literal>
+     and write its log to <filename>/var/log/app.log</filename>.
+     <screen>
+      application -l /var/log/app.log -u nobody tcp:@:210
+     </screen>
+    </para>
+    <para>
+     The server will accept Z39.50 requests and offer SRU service on port 210.
+    </para>
+   </example>
+   <example id="server.example.apache.sru"><title>Setting up Apache as SRU Frontend</title>
+    <para>
+     If you use <ulink url="&url.apache;">Apache</ulink>
+     as your public web server and want to offer HTTP port 80
+     access to the YAZ server on 210, you can use the
+     <ulink url="&url.apache.directive.proxypass;">
+      <literal>ProxyPass</literal></ulink> 
+     directive.
+     If you have virtual host
+     <literal>srw.mydomain</literal> you can use the following directives
+     in Apache's httpd.conf:
+     <screen>
+      &lt;VirtualHost *>
+       ErrorLog /home/srw/logs/error_log
+       TransferLog /home/srw/logs/access_log
+       ProxyPass / http://srw.mydomain:210/
+      &lt;/VirtualHost>
+     </screen>
+    </para>
+    <para>
+     The above for the Apache 1.3 series.
+    </para>
+   </example>
+   <example id="server.example.local.access">
+    <title>Running a server with local access only</title>
+    <para>
+     Servers that is only being accessed from the local host should listen
+     on UNIX file socket rather than a Internet socket. To listen on
+     <filename>/tmp/mysocket</filename> start the server as follows:
+     <screen>
+      application unix:/tmp/mysocket
+     </screen>
+    </para>
+   </example>
+  </sect1>
+  <sect1 id="server.vhosts"><title>GFS Configuration and Virtual Hosts</title>
+   &gfs-virtual;
+  </sect1>
+ </chapter>
+ <!-- Keep this comment at the end of the file
+ Local variables:
+ mode: sgml
+ sgml-omittag:t
+ sgml-shorttag:t
+ sgml-minimize-attributes:nil
+ sgml-always-quote-attributes:t
+ sgml-indent-step:1
+ sgml-indent-data:t
+ sgml-parent-document: "yaz.xml"
+ sgml-local-catalogs: nil
+ sgml-namecase-general:t
+ End:
+ -->
index 9bf4c96..3a23e43 100644 (file)
@@ -14,7 +14,7 @@
  &chap-introduction;
  &chap-installation;
  &chap-zoom;
- &chap-frontend;
+ &chap-server;
  &chap-asn;
  &chap-soap;
  &chap-tools;