Updates to manual. Separate PHP stylesheet.
[yaz-moved-to-github.git] / doc / frontend.xml
1 <!-- $Header: /home/cvsroot/yaz/doc/frontend.xml,v 1.2 2001-07-19 12:46:57 adam Exp $ -->
2 <chapter><title id="server">Making an IR Server for Your Database</title>
3
4 <sect1><title>Introduction</title>
5
6 <para>
7 If you aren't into documentation, a good way to learn how the
8 backend interface works is to look at the <filename>backend.h</filename>
9 file. Then, look at the small dummy-server in
10 <filename>ztest/ztest.c</filename>. Finally, you can have a look at
11 the <filename>seshigh.c</filename> file, which is where most of the
12 logic of the frontend server is located. The <filename>backend.h</filename>
13 file also makes a good reference, once you've chewed your way through
14 the prose of this file.
15 </para>
16
17 <para>
18 If you have a database system that you would like to make available by
19 means of Z39.50, &yaz; basically offers your two options. You
20 can use the APIs provided by the &asn;, &odr;, and &comstack;
21 modules to
22 create and decode PDUs, and exchange them with a client.
23 Using this low-level interface gives you access to all fields and
24 options of the protocol, and you can construct your server as close
25 to your existing database as you like.
26 It is also a fairly involved process, requiring
27 you to set up an event-handling mechanism, protocol state machine,
28 etc. To simplify server implementation, we have implemented a compact
29 and simple, but reasonably full-functioned server-frontend that will
30 handle most of the protocol mechanics, while leaving you to
31 concentrate on your database interface.
32 </para>
33
34 <note>
35 <para>
36 The backend interface was designed in anticipation of a specific
37 integration task, while still attempting to achieve some degree of
38 generality. We realise fully that there are points where the
39 interface can be improved significantly. If you have specific
40 functions or parameters that you think could be useful, send us a
41 mail (or better, sign on to the mailing list referred to in the
42 toplevel README file). We will try to fit good suggestions into future
43 releases, to the extent that it can be done without requiring
44 too many structural changes in existing applications.
45 </para>
46 </note>
47 </sect1>
48
49 <sect1><title>The Database Frontend</title>
50
51 <para>
52 We refer to this software as a generic database frontend. Your
53 database system is the <emphasis>backend database</emphasis>, and the
54 interface between the two is called the <emphasis>backend API</emphasis>.
55 The backend API consists of a small number of function handlers and
56 structure definitions. You are required to provide the
57 <function>main()</function> routine for the server (which can be
58 quite simple), as well as a set of handlers to match each of the prototypes.
59 The interface functions that you write can use any mechanism you like
60 to communicate with your database system: You might link the whole
61 thing together with your database application and access it by
62 function calls; you might use IPC to talk to a database server
63 somewhere; or you might link with third-party software that handles
64 the communication for you (like a commercial database client library).
65 At any rate, the handlers will perform the tasks of:
66 </para>
67
68 <itemizedlist>
69
70 <listitem><para>
71 Initialization.
72 </para></listitem>
73
74 <listitem><para>
75 Searching.
76 </para></listitem>
77
78 <listitem><para>
79 Fetching records.
80 </para></listitem>
81
82 <listitem><para>
83 Scanning the database index (optional - if you wish to implement SCAN).
84 </para></listitem>
85
86 <listitem><para>
87 Extended Services (optional).
88 </para></listitem>
89
90 <listitem><para>
91 Result-Set Delete (optional).
92 </para></listitem>
93
94 <listitem><para>
95 Result-Set Sort (optional).
96 </para></listitem>
97
98 </itemizedlist>
99
100 <para>
101 (more functions will be added in time to support as much of
102 Z39.50-1995 as possible).
103 </para>
104
105 </sect1>
106 <sect1><title>The Backend API</title>
107
108 <para>
109 The headers files that you need to use the interface are in the
110 <filename>include/yaz</filename> directory. They are called
111 <filename>statserv.h</filename> and <filename>backend.h</filename>. They
112 will include other files from the <filename>include/yaz</filename>
113 directory, so you'll probably want to use the -I option of your
114 compiler to tell it where to find the files. When you run
115 <literal>make</literal> in the toplevel &yaz; directory,
116 everything you need to create your server is put the
117 <filename>lib/libyaz.a</filename> library.
118 </para>
119 </sect1>
120
121 <sect1><title>Your main() Routine</title>
122
123 <para>
124 As mentioned, your <function>main()</function> routine can be quite brief.
125 If you want to initialize global parameters, or read global configuration
126 tables, this is the place to do it. At the end of the routine, you should
127 call the function
128 </para>
129
130 <synopsis>
131 int statserv_main(int argc, char **argv,
132           bend_initresult *(*bend_init)(bend_initrequest *r),
133           void (*bend_close)(void *handle));
134 </synopsis>
135
136 <para>
137 The third and fourth arguments are pointers to handlers. Handler
138 <function>bend_init</function> is called whenever the server receives
139 an Initialize Request, so it serves as a Z39.50 session initializer. The
140 <function>bend_close</function> handler is called when the session is
141 closed.
142 </para>
143
144 <para>
145 <function>statserv_main</function> will establish listening sockets
146 according to the parameters given. When connection requests are received,
147 the event handler will typically <function>fork()</function> and
148 create a sub-process to handle a new connection.
149 Alternatively the server may be setup to create threads for each connection.
150 If you do use global variables and forking, you should be aware, then,
151 that these cannot be shared between associations, unless you explicitly
152 disable forking by command line parameters. 
153 </para>
154
155 <para>
156 The server provides a mechanism for controlling some of its behavior
157 without using command-line options. The function
158 </para>
159
160 <synopsis>
161 statserv_options_block *statserv_getcontrol(void);
162 </synopsis>
163
164 <para>
165 Will return a pointer to a <literal>struct statserv_options_block</literal>
166 describing the current default settings of the server. The structure
167 contains these elements:
168
169 <variablelist>
170 <varlistentry><term>int dynamic</term><listitem><para>
171 A boolean value, which determines whether the server
172 will fork on each incoming request (TRUE), or not (FALSE). Default is
173 TRUE. This flag is only read by UNIX-based servers (WIN32 based servers
174 doesn't fork).
175 </para></listitem></varlistentry>
176
177 <varlistentry><term>int threads</term><listitem><para>
178 A boolean value, which determines whether the server
179 will create a thread on each incoming request (TRUE), or not (FALSE).
180 Default is FALSE. This flag is only read by UNIX-based servers that offer
181 POSIX Threads support. WIN32-based servers always operate in threaded mode.
182 </para></listitem></varlistentry>
183
184 <varlistentry><term>int inetd</term><listitem><para>
185 A boolean value, which determines whether the server
186 will operates under a UNIX INET daemon (inetd). Default is FALSE.
187 </para></listitem></varlistentry>
188
189 <varlistentry><term>int loglevel</term><listitem><para>
190 Set this by ORing the constants defined in
191 <filename>include/yaz/yaz-log.h</filename>.
192 </para></listitem></varlistentry>
193
194 <varlistentry><term>char logfile&lsqb;ODR_MAXNAME+1&rsqb;</term>
195 <listitem><para>File for diagnostic output (&quot;&quot;: stderr).
196 </para></listitem></varlistentry>
197 <varlistentry><term>char apdufile&lsqb;ODR_MAXNAME+1&rsqb;</term>
198 <listitem><para>
199 Name of file for logging incoming and outgoing APDUs (&quot;&quot;: don't
200 log APDUs, &quot;-&quot;: <literal>stderr</literal>).
201 </para></listitem></varlistentry>
202
203 <varlistentry><term>char default_listen&lsqb;1024&rsqb;</term>
204 <listitem><para>Same form as the command-line specification of
205 listener address. &quot;&quot;: no default listener address.
206 Default is to listen at &quot;tcp:@:9999&quot;. You can only
207 specify one default listener address in this fashion.
208 </para></listitem></varlistentry>
209
210 <varlistentry><term>enum oid_proto default_proto;</term>
211 <listitem><para>Either <literal>PROTO_SR</literal> or
212 <literal>PROTO_Z3950</literal>. Default is <literal>PROTO_Z39_50</literal>.
213 </para></listitem></varlistentry>
214 <varlistentry><term>int idle_timeout;</term>
215 <listitem><para>Maximum session idletime, in minutes. Zero indicates
216 no (infinite) timeout. Default is 120 minutes.
217 </para></listitem></varlistentry>
218
219 <varlistentry><term>int maxrecordsize;</term>
220 <listitem><para>Maximum permissible record (message) size. Default
221 is 1Mb. This amount of memory will only be allocated if a client requests a
222 very large amount of records in one operation (or a big record). Set it
223 to a lower number
224 if you are worried about resource consumption on your host system.
225 </para></listitem></varlistentry>
226
227 <varlistentry><term>char configname&lsqb;ODR_MAXNAME+1&rsqb;</term>
228 <listitem><para>Passed to the backend when a new connection is received.
229 </para></listitem></varlistentry>
230
231 <varlistentry><term>char setuid&lsqb;ODR_MAXNAME+1&rsqb;</term>
232 <listitem><para>Set user id to the user specified, after binding
233 the listener addresses.
234 </para></listitem></varlistentry>
235
236 <varlistentry><term>void (*bend_start)(struct statserv_options_block *p)</term>
237 <listitem><para>Pointer to function which is called after the command line
238 options have been parsed - but before the server starts listening. For
239 forked UNIX servers this handler is called in the mother process; for
240 threaded servers this handler is called in the main thread. The default
241 value of this pointer is NULL in which case it isn't invoked by the frontend
242 server. When the server operates as an NT service this handler is called
243 whenever the service is started. 
244 </para></listitem></varlistentry>
245
246 <varlistentry><term>void (*bend_stop)(struct statserv_options_block *p)</term>
247 <listitem><para>Pointer to function which is called whenver the server
248 has stopped listening for incoming connections. This function pointer
249 has a default value of NULL in which case it isn't called.
250 When the server operates as an NT service this handler is called
251 whenever the service is stopped.
252 </para></listitem></varlistentry>
253
254 <varlistentry><term>void *handle</term>
255 <listitem><para>User defined pointer (default value NULL).
256 This is a per-server handle that can be used to specify "user-data".
257 Do not confuse this with the session-handle as returned by bend_init.
258 </para></listitem></varlistentry>
259
260 </variablelist>
261 </para>
262
263 <para>
264 The pointer returned by <literal>statserv_getcontrol</literal> points to
265 a static area. You are allowed to change the contents of the structure,
266 but the changes will not take effect before you call
267 </para>
268
269 <synopsis>
270 void statserv_setcontrol(statserv_options_block *block);
271 </synopsis>
272
273 <note>
274 <para>
275 that you should generally update this structure before calling
276 <function>statserv_main()</function>.
277 </para>
278 </note>
279 </sect1>
280
281 <sect1><title>The Backend Functions</title>
282
283 <para>
284 For each service of the protocol, the backend interface declares one or
285 two functions. You are required to provide implementations of the
286 functions representing the services that you wish to implement.
287 </para>
288
289 <sect2><title>Init</title>
290
291 <synopsis>
292 bend_initresult (*bend_init)(bend_initrequest *r);
293 </synopsis>
294
295 <para>
296 This handler is called once for each new connection request, after
297 a new process/thread has been created, and an Initialize Request has been
298 received from the client. The pointer to the <function>bend_init</function>
299 handler is passed in the call to <function>statserv_start</function>.
300 </para>
301 <para>
302 Unlike previous versions of YAZ, the <function>bend_init</function> also
303 serves as a handler that defines the Z39.50 services that the backend
304 wish to support. Pointers to <emphasis>all</emphasis> service handlers,
305 including search - and fetch must be specified here in this handler.
306 </para>
307 <para>
308 The request  - and result structures are defined as
309 </para>
310
311 <synopsis>
312 typedef struct bend_initrequest
313 {
314     Z_IdAuthentication *auth;
315     ODR stream;                /* encoding stream */
316     ODR print;                 /* printing stream */
317     Z_ReferenceId *referenceId;/* reference ID */
318     char *peer_name;           /* dns host of peer (client) */
319
320     char *implementation_name;
321     char *implementation_version;
322     int (*bend_sort) (void *handle, bend_sort_rr *rr);
323     int (*bend_search) (void *handle, bend_search_rr *rr);
324     int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
325     int (*bend_present) (void *handle, bend_present_rr *rr);
326     int (*bend_esrequest) (void *handle, bend_esrequest_rr *rr);
327     int (*bend_delete)(void *handle, bend_delete_rr *rr);
328     int (*bend_scan)(void *handle, bend_scan_rr *rr);
329     int (*bend_segment)(void *handle, bend_segment_rr *rr);
330 } bend_initrequest;
331
332 typedef struct bend_initresult
333 {
334     int errcode;       /* 0==OK */
335     char *errstring;   /* system error string or NULL */
336     void *handle;      /* private handle to the backend module */
337 } bend_initresult;
338 </synopsis>
339
340 <para>
341 In general, the server frontend expects that the
342 <literal>bend_*result</literal> pointer that you return is valid at
343 least until the next call to a <literal>bend_* function</literal>.
344 This applies to all of the functions described herein. The parameter
345 structure passed to you in the call belongs to the server frontend, and
346 you should not make assumptions about its contents after the current
347 function call has completed. In other words, if you want to retain any
348 of the contents of a request structure, you should copy them.
349 </para>
350
351 <para>
352 The <literal>errcode</literal> should be zero if the initialization of
353 the backend went well. Any other value will be interpreted as an error.
354 The <literal>errstring</literal> isn't used in the current version, but one
355 optin would be to stick it in the initResponse as a VisibleString.
356 The <literal>handle</literal> is the most important parameter. It should
357 be set to some value that uniquely identifies the current session to
358 the backend implementation. It is used by the frontend server in any
359 future calls to a backend function.
360 The typical use is to set it to point to a dynamically allocated state
361 structure that is private to your backend module.
362 </para>
363
364 <para>
365 The <literal>auth</literal> member holds the authentication information
366 part of the Z39.50 Initialize Request. Interpret this if your serves
367 requires authentication. 
368 </para>
369
370 <para>
371 The members <literal>peer_name</literal>,
372 <literal>implementation_name</literal> and
373 <literal>implementation_version</literal> holds DNS of client, name
374 of client (Z39.50) implementation - and version.
375 </para>
376
377 <para>
378 The <literal>bend_</literal> - members are set to NULL when
379 <function>bend_init</function> is called. Modify the pointers by setting them
380 to point to backend functions.
381 </para>
382
383 </sect2>
384
385 <sect2><title>Search and retrieve</title>
386
387 <para>We now describe the handlers that are required to support search -
388 and retrieve. You must support two functions - one for seearch - and one
389 for fetch (retrieval of one record). If desirable you can provide a
390 third handler which is called when a present request is received which
391 allows you to optimize retrieval of multiple-records.
392 </para>
393
394 <synopsis>
395 int (*bend_search) (void *handle, bend_search_rr *rr);
396
397 typedef struct {
398     char *setname;             /* name to give to this set */
399     int replace_set;           /* replace set, if it already exists */
400     int num_bases;             /* number of databases in list */
401     char **basenames;          /* databases to search */
402     Z_ReferenceId *referenceId;/* reference ID */
403     Z_Query *query;            /* query structure */
404     ODR stream;                /* encode stream */
405     ODR decode;                /* decode stream */
406     ODR print;                 /* print stream */
407
408     bend_request request;
409     bend_association association;
410     int *fd;
411     int hits;                  /* number of hits */
412     int errcode;               /* 0==OK */
413     char *errstring;           /* system error string or NULL */
414 } bend_search_rr;
415
416 </synopsis>
417
418 <para>
419 The <function>bend_search</function> handler is a fairly close
420 approximation of a protocol Search Request - and Response PDUs
421 The <literal>setname</literal> is the resultSetName from the protocol.
422 You are required to establish a mapping between the set name and whatever
423 your backend database likes to use.
424 Similarly, the <literal>replace_set</literal> is a boolean value
425 corresponding to the resultSetIndicator field in the protocol.
426 <literal>num_bases/basenames</literal> is a length of/array of character
427 pointers to the database names provided by the client.
428 The <literal>query</literal> is the full query structure as defined in the
429 protocol ASN.1 specification.
430 It can be either of the possible query types, and it's up to you to
431 determine if you can handle the provided query type.
432 Rather than reproduce the C interface here, we'll refer you to the
433 structure definitions in the file
434 <filename>include/yaz/z-core.h</filename>. If you want to look at the
435 attributeSetId OID of the RPN query, you can either match it against
436 your own internal tables, or you can use the
437 <literal>oid_getentbyoid</literal> function provided by &yaz;.
438 </para>
439
440 <para>
441 The structure contains a number of hits, and an
442 <literal>errcode/errstring</literal> pair. If an error occurs
443 during the search, or if you're unhappy with the request, you should
444 set the errcode to a value from the BIB-1 diagnostic set. The value
445 will then be returned to the user in a nonsurrogate diagnostic record
446 in the response. The <literal>errstring</literal>, if provided, will
447 go in the addinfo field. Look at the protocol definition for the
448 defined error codes, and the suggested uses of the addinfo field.
449 </para>
450
451
452 <synopsis>
453 int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
454
455 typedef struct bend_fetch_rr {
456     char *setname;             /* set name */
457     int number;                /* record number */
458     Z_ReferenceId *referenceId;/* reference ID */
459     oid_value request_format;  /* One of the CLASS_RECSYN members */
460     int *request_format_raw;   /* same as above (raw OID) */
461     Z_RecordComposition *comp; /* Formatting instructions */
462     ODR stream;                /* encoding stream - memory source if req */
463     ODR print;                 /* printing stream */
464
465     char *basename;            /* name of database that provided record */
466     int len;                   /* length of record or -1 if structured */
467     char *record;              /* record */
468     int last_in_set;           /* is it?  */
469     oid_value output_format;   /* format */
470     int *output_format_raw;    /* used instead of above if not-null */
471     int errcode;               /* 0==success */
472     char *errstring;           /* system error string or NULL */
473     int surrogate_flag;        /* surrogate diagnostic */
474 } bend_fetch_rr;
475 </synopsis>
476
477 <para>
478 The frontend server calls the <function>bend_fetch</function> handler when
479 it needs database records to fulfill a Search Request or a Present Request.
480 The <literal>setname</literal> is simply the name of the result set
481 that holds the reference to the desired record.
482 The <literal>number</literal> is the offset into the set (with 1
483 being the first record in the set). The <literal>format</literal> field
484 is the record format requested by the client (See section
485 <link linkend="oid">Object Identifiers</link>). The value
486 <literal>VAL_NONE</literal> indicates that the client did not
487 request a specific format. The <literal>stream</literal> argument
488 is an &odr; stream which should be used for
489 allocating space for structured data records. The stream will be reset when
490 all records have been assembled, and the response package has been transmitted.
491 For unstructured data, the backend is responsible for maintaining a static
492 or dynamic buffer for the record between calls.
493 </para>
494
495 <para>
496 In the structure, the <literal>basename</literal> is the name of the
497 database that holds the
498 record. <literal>len</literal> is the length of the record returned, in
499 bytes, and <literal>record</literal> is a pointer to the record.
500 <literal>Last_in_set</literal> should be nonzero only if the record
501 returned is the last one in the given result set. <literal>errcode</literal>
502 and <literal>errstring</literal>, if given, will be
503 interpreted as a global error pertaining to the set, and will be returned
504 in a non-surrogate-diagnostic. If you wish to return the error as a
505 surrogate-diagnostic (local error) you can do this by setting
506 <literal>surrogate_flag</literal> to 1 also.
507 </para>
508
509 <para>
510 If the <literal>len</literal> field has the value -1, then
511 <literal>record</literal> is assumed to point to a constructed data
512 type. The <literal>format</literal> field will be used to determine
513 which encoder should be used to serialize the data.
514 </para>
515
516 <note>
517 <para>
518 If your backend generates structured records, it should use
519 <function>odr_malloc()</function> on the provided stream for allocating
520 data: This allows the frontend server to keep track of the record sizes.
521 </para>
522 </note>
523
524 <para>
525 The <literal>format</literal> field is mapped to an object identifier
526 in the direct reference of the resulting EXTERNAL representation of the record.
527 </para>
528
529 <note>
530 <para>
531 The current version of &yaz; only supports the direct reference mode.
532 </para>
533 </note>
534
535 <synopsis>
536 int (*bend_present) (void *handle, bend_present_rr *rr);
537
538 typedef struct {
539     char *setname;             /* set name */
540     int start;
541     int number;                /* record number */
542     oid_value format;          /* One of the CLASS_RECSYN members */
543     Z_ReferenceId *referenceId;/* reference ID */
544     Z_RecordComposition *comp; /* Formatting instructions */
545     ODR stream;                /* encoding stream - memory source if required */
546     ODR print;                 /* printing stream */
547     bend_request request;
548     bend_association association;
549
550     int hits;                  /* number of hits */
551     int errcode;               /* 0==OK */
552     char *errstring;           /* system error string or NULL */
553 } bend_present_rr;
554 </synopsis>
555
556 <para>
557 The <function>bend_present</function> handler is called when
558 the server receives a Present Request. The <literal>setname</literal>,
559 <literal>start</literal> and <literal>number</literal> is the
560 name of the result set - start position - and number of records to
561 be retrieved respectively. <literal>format</literal> and
562 <literal>comp</literal> is the preferred transfer syntax and element
563 specifications of the present request.
564 </para>
565 <para>
566 Note that this is handler serves as a supplement for
567 <function>bend_fetch</function> and need not to be defined in order to
568 support search - and retrieve. 
569 </para>
570
571 </sect2>
572
573 <sect2><title>Delete</title>
574
575 <para>
576 For backends that supports delete of a result set only one handler
577 must be defined.
578 </para>
579
580 <synopsis>
581 int (*bend_delete)(void *handle, bend_delete_rr *rr);
582
583 typedef struct bend_delete_rr {
584     int function;
585     int num_setnames;
586     char **setnames;
587     Z_ReferenceId *referenceId;
588     int delete_status;      /* status for the whole operation */
589     int *statuses;          /* status each set - indexed as setnames */
590     ODR stream;
591     ODR print; 
592 } bend_delete_rr;
593 </synopsis>
594
595 <note>
596 <para>
597 The delete set function definition is rather primitive, mostly because we
598 have had no practical need for it as of yet. If someone wants
599 to provide a full delete service, we'd be happy to add the
600 extra parameters that are required. Are there clients out there
601 that will actually delete sets they no longer need?
602 </para>
603 </note>
604
605 </sect2>
606
607 <sect2><title>scan</title>
608
609 <para>
610 For servers that wish to offer the scan service one handler
611 must be defined.
612 </para>
613
614 <synopsis>
615 int (*bend_delete)(void *handle, bend_delete_rr *rr);
616
617 typedef enum {
618     BEND_SCAN_SUCCESS,  /* ok */
619     BEND_SCAN_PARTIAL   /* not all entries could be found */
620 } bend_scan_status;
621
622 typedef struct bend_scan_rr {
623     int num_bases;      /* number of elements in databaselist */
624     char **basenames;   /* databases to search */
625     oid_value attributeset;
626     Z_ReferenceId *referenceId; /* reference ID */
627     Z_AttributesPlusTerm *term;
628     ODR stream;         /* encoding stream - memory source if required */
629     ODR print;          /* printing stream */
630
631     int *step_size;     /* step size */
632     int term_position;  /* desired index of term in result list/returned */
633     int num_entries;    /* number of entries requested/returned */
634
635     struct scan_entry *entries;
636     bend_scan_status status;
637     int errcode;
638     char *errstring;
639 } bend_scan_rr;
640 </synopsis>
641 </sect2>
642 </sect1>
643
644 <sect1><title>Application Invocation</title>
645
646 <para>
647 The finished application has the following
648 invocation syntax (by way of <function>statserv_main()</function>):
649 </para>
650
651 <synopsis>
652 <replaceable>appname</replaceable> &lsqb;-szSiTu -a <replaceable>apdufile</replaceable> -l <replaceable>logfile</replaceable> -v <replaceable>loglevel</replaceable> -c <replaceable>config</replaceable>&rsqb;
653 &lsqb;listener ...&rsqb;
654 </synopsis>
655
656 <para>
657 The options are
658
659 <variablelist>
660
661 <varlistentry><term>-a <replaceable>file</replaceable></term>
662  <listitem><para>
663 Specify a file for dumping PDUs (for diagnostic purposes).
664 The special name &quot;-&quot; sends output to <literal>stderr</literal>.
665 </para></listitem></varlistentry>
666
667 <varlistentry><term>-S</term>
668  <listitem><para>
669 Don't fork or make threads on connection requests. This is good for
670 debugging, but not recommended for real operation: Although the server is
671 asynchronous and non-blocking, it can be nice to keep a software
672 malfunction (okay then, a crash) from affecting all current users.
673 </para></listitem></varlistentry>
674
675 <varlistentry><term>-T</term>
676 <listitem><para>
677 Operate the server in threaded mode. The server creates a thread
678 for each connection rather than a fork a process. Only available
679 on UNIX systems that offers POSIX threads.
680 </para></listitem></varlistentry>
681
682 <varlistentry><term>-s</term>
683 <listitem><para>
684 Use the SR protocol (obsolete).
685 </para></listitem></varlistentry>
686
687 <varlistentry><term>-z</term>
688 <listitem><para>
689 Use the Z39.50 protocol (default). These two options complement
690 each other. You can use both multiple times on the same command
691 line, between listener-specifications (see below). This way, you
692 can set up the server to listen for connections in both protocols
693 concurrently, on different local ports.
694 </para></listitem></varlistentry>
695
696 <varlistentry><term>-l <replaceable>file</replaceable></term>
697 <listitem><para>The logfile.
698 </para></listitem></varlistentry>
699
700 <varlistentry><term>-c <replaceable>config</replaceable></term>
701 <listitem><para>A user option that serves as a specifier for some
702 sort of configuration, e.g. a filename.
703 The argument to this option is transferred to member
704 <literal>configname</literal>of the <literal>statserv_options_block</literal>.
705 </para></listitem></varlistentry>
706
707 <varlistentry><term>-v <replaceable>level</replaceable></term>
708 <listitem><para>
709 The log level. Use a comma-separated list of members of the set
710 {fatal,debug,warn,log,all,none}.
711 </para></listitem></varlistentry>
712
713 <varlistentry><term>-u <replaceable>userid</replaceable></term>
714 <listitem><para>
715 Set user ID. Sets the real UID of the server process to that of the
716 given user. It's useful if you aren't comfortable with having the
717 server run as root, but you need to start it as such to bind a
718 privileged port.
719 </para></listitem></varlistentry>
720
721 <varlistentry><term>-w <replaceable>dir</replaceable></term>
722 <listitem><para>
723 Working directory.
724 </para></listitem></varlistentry>
725
726 <varlistentry><term>-i</term>
727 <listitem><para>
728 Use this when running from the <application>inetd</application> server.
729 </para></listitem></varlistentry>
730
731 <varlistentry><term>-t <replaceable>minutes</replaceable></term>
732 <listitem><para>
733 Idle session timeout, in minutes.
734 </para></listitem></varlistentry>
735
736 <varlistentry><term>-k <replaceable>size</replaceable></term>
737 <listitem><para>
738 Maximum record size/message size, in kilobytes.
739 </para></listitem></varlistentry>
740
741
742 </variablelist>
743 </para>
744
745 <para>
746 A listener specification consists of a transport mode followed by a
747 colon (:) followed by a listener address. The transport mode is
748 either <literal>osi</literal> or <literal>tcp</literal>.
749 </para>
750
751 <para>
752 For TCP, an address has the form
753 </para>
754
755 <synopsis>
756   hostname | IP-number &lsqb;: portnumber&rsqb;
757 </synopsis>
758
759 <para>
760 The port number defaults to 210 (standard Z39.50 port).
761 </para>
762
763 <para>
764 For osi, the address form is
765 </para>
766
767 <synopsis>
768   &lsqb;t-selector /&rsqb; hostname | IP-number &lsqb;: portnumber&rsqb;
769 </synopsis>
770
771 <para>
772 The transport selector is given as a string of hex digits (with an even
773 number of digits). The default port number is 102 (RFC1006 port).
774 </para>
775
776 <para>
777 Examples
778 </para>
779
780 <screen>
781   tcp:dranet.dra.com
782
783   osi:0402/dbserver.osiworld.com:3000
784 </screen>
785
786 <para>
787 In both cases, the special hostname &quot;@&quot; is mapped to
788 the address INADDR_ANY, which causes the server to listen on any local
789 interface. To start the server listening on the registered ports for
790 Z39.50 and SR over OSI/RFC1006, and to drop root privileges once the
791 ports are bound, execute the server like this (from a root shell):
792 </para>
793
794 <screen>
795   my-server -u daemon tcp:@ -s osi:@
796 </screen>
797
798 <para>
799 You can replace <literal>daemon</literal> with another user, eg. your
800 own account, or a dedicated IR server account.
801 <literal>my-server</literal> should be the name of your
802 server application. You can test the procedure with the
803 <application>yaz-ztest</application> application.
804 </para>
805
806 </sect1>
807 </chapter>
808