1 <chapter id="server"><title>Generic server</title>
2 <sect1 id="server.introduction"><title>Introduction</title>
5 If you aren't into documentation, a good way to learn how the
6 back end interface works is to look at the <filename>backend.h</filename>
7 file. Then, look at the small dummy-server in
8 <filename>ztest/ztest.c</filename>. The <filename>backend.h</filename>
9 file also makes a good reference, once you've chewed your way through
10 the prose of this file.
14 If you have a database system that you would like to make available by
15 means of Z39.50 or SRU, &yaz; basically offers your two options. You
16 can use the APIs provided by the &asn;, &odr;, and &comstack;
18 create and decode PDUs, and exchange them with a client.
19 Using this low-level interface gives you access to all fields and
20 options of the protocol, and you can construct your server as close
21 to your existing database as you like.
22 It is also a fairly involved process, requiring
23 you to set up an event-handling mechanism, protocol state machine,
24 etc. To simplify server implementation, we have implemented a compact
25 and simple, but reasonably full-functioned server-frontend that will
26 handle most of the protocol mechanics, while leaving you to
27 concentrate on your database interface.
32 The backend interface was designed in anticipation of a specific
33 integration task, while still attempting to achieve some degree of
34 generality. We realize fully that there are points where the
35 interface can be improved significantly. If you have specific
36 functions or parameters that you think could be useful, send us a
37 mail (or better, sign on to the mailing list referred to in the
38 top-level README file). We will try to fit good suggestions into future
39 releases, to the extent that it can be done without requiring
40 too many structural changes in existing applications.
46 The &yaz; server does not support XCQL.
51 <sect1 id="server.frontend"><title>The Database Frontend</title>
54 We refer to this software as a generic database frontend. Your
55 database system is the <emphasis>backend database</emphasis>, and the
56 interface between the two is called the <emphasis>backend API</emphasis>.
57 The backend API consists of a small number of function handlers and
58 structure definitions. You are required to provide the
59 <function>main()</function> routine for the server (which can be
60 quite simple), as well as a set of handlers to match each of the
62 The interface functions that you write can use any mechanism you like
63 to communicate with your database system: You might link the whole
64 thing together with your database application and access it by
65 function calls; you might use IPC to talk to a database server
66 somewhere; or you might link with third-party software that handles
67 the communication for you (like a commercial database client library).
68 At any rate, the handlers will perform the tasks of:
86 Scanning the database index (optional - if you wish to implement SCAN).
90 Extended Services (optional).
94 Result-Set Delete (optional).
98 Result-Set Sort (optional).
102 Return Explain for SRU (optional).
108 (more functions will be added in time to support as much of
109 Z39.50-1995 as possible).
113 <sect1 id="server.backend"><title>The Backend API</title>
116 The header file that you need to use the interface are in the
117 <filename>include/yaz</filename> directory. It's called
118 <filename>backend.h</filename>. It will include other files from
119 the <filename>include/yaz</filename> directory, so you'll
120 probably want to use the -I option of your compiler to tell it
121 where to find the files. When you run
122 <literal>make</literal> in the top-level &yaz; directory,
123 everything you need to create your server is to link with the
124 <filename>lib/libyaz.la</filename> library.
128 <sect1 id="server.main"><title>Your main() Routine</title>
131 As mentioned, your <function>main()</function> routine can be quite brief.
132 If you want to initialize global parameters, or read global configuration
133 tables, this is the place to do it. At the end of the routine, you should
138 int statserv_main(int argc, char **argv,
139 bend_initresult *(*bend_init)(bend_initrequest *r),
140 void (*bend_close)(void *handle));
144 The third and fourth arguments are pointers to handlers. Handler
145 <function>bend_init</function> is called whenever the server receives
146 an Initialize Request, so it serves as a Z39.50 session initializer. The
147 <function>bend_close</function> handler is called when the session is
152 <function>statserv_main</function> will establish listening sockets
153 according to the parameters given. When connection requests are received,
154 the event handler will typically <function>fork()</function> and
155 create a sub-process to handle a new connection.
156 Alternatively the server may be setup to create threads for each
158 If you do use global variables and forking, you should be aware, then,
159 that these cannot be shared between associations, unless you explicitly
160 disable forking by command line parameters.
164 The server provides a mechanism for controlling some of its behavior
165 without using command-line options. The function
169 statserv_options_block *statserv_getcontrol(void);
173 will return a pointer to a <literal>struct statserv_options_block</literal>
174 describing the current default settings of the server. The structure
175 contains these elements:
179 <literal>int dynamic</literal></term><listitem><para>
180 A boolean value, which determines whether the server
181 will fork on each incoming request (TRUE), or not (FALSE). Default is
182 TRUE. This flag is only read by UNIX-based servers (WIN32 based servers
184 </para></listitem></varlistentry>
187 <literal>int threads</literal></term><listitem><para>
188 A boolean value, which determines whether the server
189 will create a thread on each incoming request (TRUE), or not (FALSE).
190 Default is FALSE. This flag is only read by UNIX-based servers
191 that offer POSIX Threads support.
192 WIN32-based servers always operate in threaded mode.
193 </para></listitem></varlistentry>
196 <literal>int inetd</literal></term><listitem><para>
197 A boolean value, which determines whether the server
198 will operates under a UNIX INET daemon (inetd). Default is FALSE.
199 </para></listitem></varlistentry>
202 <literal>char logfile[ODR_MAXNAME+1]</literal></term>
203 <listitem><para>File for diagnostic output ("": stderr).
204 </para></listitem></varlistentry>
207 <literal>char apdufile[ODR_MAXNAME+1]</literal></term>
209 Name of file for logging incoming and outgoing APDUs
210 ("": don't log APDUs, "-":
211 <literal>stderr</literal>).
212 </para></listitem></varlistentry>
215 <literal>char default_listen[1024]</literal></term>
216 <listitem><para>Same form as the command-line specification of
217 listener address. "": no default listener address.
218 Default is to listen at "tcp:@:9999". You can only
219 specify one default listener address in this fashion.
220 </para></listitem></varlistentry>
223 <literal>enum oid_proto default_proto;</literal></term>
224 <listitem><para>Either <literal>PROTO_Z3950</literal> or
225 <literal>PROTO_SR</literal>.
226 Default is <literal>PROTO_Z39_50</literal>.
227 </para></listitem></varlistentry>
230 <literal>int idle_timeout;</literal></term>
231 <listitem><para>Maximum session idle-time, in minutes. Zero indicates
232 no (infinite) timeout. Default is 15 minutes.
233 </para></listitem></varlistentry>
236 <literal>int maxrecordsize;</literal></term>
237 <listitem><para>Maximum permissible record (message) size. Default
238 is 64 MB. This amount of memory will only be allocated if a
239 client requests a very large amount of records in one operation
241 Set it to a lower number if you are worried about resource
242 consumption on your host system.
243 </para></listitem></varlistentry>
246 <literal>char configname[ODR_MAXNAME+1]</literal></term>
247 <listitem><para>Passed to the backend when a new connection is received.
248 </para></listitem></varlistentry>
251 <literal>char setuid[ODR_MAXNAME+1]</literal></term>
252 <listitem><para>Set user id to the user specified, after binding
253 the listener addresses.
254 </para></listitem></varlistentry>
257 <literal>void (*bend_start)(struct statserv_options_block *p)</literal>
259 <listitem><para>Pointer to function which is called after the
260 command line options have been parsed - but before the server
262 For forked UNIX servers this handler is called in the mother
263 process; for threaded servers this handler is called in the
265 The default value of this pointer is NULL in which case it
266 isn't invoked by the frontend server.
267 When the server operates as an NT service this handler is called
268 whenever the service is started.
269 </para></listitem></varlistentry>
272 <literal>void (*bend_stop)(struct statserv_options_block *p)</literal>
274 <listitem><para>Pointer to function which is called whenever the server
275 has stopped listening for incoming connections. This function pointer
276 has a default value of NULL in which case it isn't called.
277 When the server operates as an NT service this handler is called
278 whenever the service is stopped.
279 </para></listitem></varlistentry>
282 <literal>void *handle</literal></term>
283 <listitem><para>User defined pointer (default value NULL).
284 This is a per-server handle that can be used to specify "user-data".
285 Do not confuse this with the session-handle as returned by bend_init.
286 </para></listitem></varlistentry>
292 The pointer returned by <literal>statserv_getcontrol</literal> points to
293 a static area. You are allowed to change the contents of the structure,
294 but the changes will not take effect before you call
298 void statserv_setcontrol(statserv_options_block *block);
303 that you should generally update this structure before calling
304 <function>statserv_main()</function>.
309 <sect1 id="server.backendfunctions"><title>The Backend Functions</title>
312 For each service of the protocol, the backend interface declares one or
313 two functions. You are required to provide implementations of the
314 functions representing the services that you wish to implement.
317 <sect2 id="server.init"><title>Init</title>
320 bend_initresult (*bend_init)(bend_initrequest *r);
324 This handler is called once for each new connection request, after
325 a new process/thread has been created, and an Initialize Request has
326 been received from the client. The pointer to the
327 <function>bend_init</function> handler is passed in the call to
328 <function>statserv_start</function>.
332 This handler is also called when operating in SRU mode - when
333 a connection has been made (even though SRU does not offer
338 Unlike previous versions of YAZ, the <function>bend_init</function> also
339 serves as a handler that defines the Z39.50 services that the backend
340 wish to support. Pointers to <emphasis>all</emphasis> service handlers,
341 including search - and fetch must be specified here in this handler.
344 The request - and result structures are defined as
348 typedef struct bend_initrequest
350 /** \brief user/name/password to be read */
351 Z_IdAuthentication *auth;
352 /** \brief encoding stream (for results) */
354 /** \brief printing stream */
356 /** \brief decoding stream (use stream for results) */
358 /** \brief reference ID */
359 Z_ReferenceId *referenceId;
360 /** \brief peer address of client */
363 /** \brief character set and language negotiation
365 see include/yaz/z-charneg.h
367 Z_CharSetandLanguageNegotiation *charneg_request;
369 /** \brief character negotiation response */
370 Z_External *charneg_response;
372 /** \brief character set (encoding) for query terms
374 This is NULL by default. It should be set to the native character
375 set that the backend assumes for query terms */
378 /** \brief whehter query_charset also applies to recors
380 Is 0 (No) by default. Set to 1 (yes) if records is in the same
381 character set as queries. If in doubt, use 0 (No).
383 int records_in_same_charset;
385 char *implementation_id;
386 char *implementation_name;
387 char *implementation_version;
389 /** \brief Z39.50 sort handler */
390 int (*bend_sort)(void *handle, bend_sort_rr *rr);
391 /** \brief SRU/Z39.50 search handler */
392 int (*bend_search)(void *handle, bend_search_rr *rr);
393 /** \brief SRU/Z39.50 fetch handler */
394 int (*bend_fetch)(void *handle, bend_fetch_rr *rr);
395 /** \brief SRU/Z39.50 present handler */
396 int (*bend_present)(void *handle, bend_present_rr *rr);
397 /** \brief Z39.50 extended services handler */
398 int (*bend_esrequest) (void *handle, bend_esrequest_rr *rr);
399 /** \brief Z39.50 delete result set handler */
400 int (*bend_delete)(void *handle, bend_delete_rr *rr);
401 /** \brief Z39.50 scan handler */
402 int (*bend_scan)(void *handle, bend_scan_rr *rr);
403 /** \brief Z39.50 segment facility handler */
404 int (*bend_segment)(void *handle, bend_segment_rr *rr);
405 /** \brief SRU explain handler */
406 int (*bend_explain)(void *handle, bend_explain_rr *rr);
407 /** \brief SRU scan handler */
408 int (*bend_srw_scan)(void *handle, bend_scan_rr *rr);
409 /** \brief SRU record update handler */
410 int (*bend_srw_update)(void *handle, bend_update_rr *rr);
412 /** \brief whether named result sets are supported (0=disable, 1=enable) */
413 int named_result_sets;
416 typedef struct bend_initresult
418 int errcode; /* 0==OK */
419 char *errstring; /* system error string or NULL */
420 void *handle; /* private handle to the backend module */
425 In general, the server frontend expects that the
426 <literal>bend_*result</literal> pointer that you return is valid at
427 least until the next call to a <literal>bend_* function</literal>.
428 This applies to all of the functions described herein. The parameter
429 structure passed to you in the call belongs to the server frontend, and
430 you should not make assumptions about its contents after the current
431 function call has completed. In other words, if you want to retain any
432 of the contents of a request structure, you should copy them.
436 The <literal>errcode</literal> should be zero if the initialization of
437 the backend went well. Any other value will be interpreted as an error.
438 The <literal>errstring</literal> isn't used in the current version, but
439 one option would be to stick it in the initResponse as a VisibleString.
440 The <literal>handle</literal> is the most important parameter. It should
441 be set to some value that uniquely identifies the current session to
442 the backend implementation. It is used by the frontend server in any
443 future calls to a backend function.
444 The typical use is to set it to point to a dynamically allocated state
445 structure that is private to your backend module.
449 The <literal>auth</literal> member holds the authentication information
450 part of the Z39.50 Initialize Request. Interpret this if your serves
451 requires authentication.
455 The members <literal>peer_name</literal>,
456 <literal>implementation_id</literal>,
457 <literal>implementation_name</literal> and
458 <literal>implementation_version</literal> holds
459 DNS of client, ID of implementor, name
460 of client (Z39.50) implementation - and version.
464 The <literal>bend_</literal> - members are set to NULL when
465 <function>bend_init</function> is called. Modify the pointers by
466 setting them to point to backend functions.
471 <sect2 id="server.search.retrieve"><title>Search and Retrieve</title>
473 <para>We now describe the handlers that are required to support search -
474 and retrieve. You must support two functions - one for search - and one
475 for fetch (retrieval of one record). If desirable you can provide a
476 third handler which is called when a present request is received which
477 allows you to optimize retrieval of multiple-records.
481 int (*bend_search) (void *handle, bend_search_rr *rr);
484 char *setname; /* name to give to this set */
485 int replace_set; /* replace set, if it already exists */
486 int num_bases; /* number of databases in list */
487 char **basenames; /* databases to search */
488 Z_ReferenceId *referenceId;/* reference ID */
489 Z_Query *query; /* query structure */
490 ODR stream; /* encode stream */
491 ODR decode; /* decode stream */
492 ODR print; /* print stream */
494 bend_request request;
495 bend_association association;
497 int hits; /* number of hits */
498 int errcode; /* 0==OK */
499 char *errstring; /* system error string or NULL */
500 Z_OtherInformation *search_info; /* additional search info */
501 char *srw_sortKeys; /* holds SRU/SRW sortKeys info */
502 char *srw_setname; /* holds SRU/SRW generated resultsetID */
503 int *srw_setnameIdleTime; /* holds SRU/SRW life-time */
504 int estimated_hit_count; /* if hit count is estimated */
505 int partial_resultset; /* if result set is partial */
510 The <function>bend_search</function> handler is a fairly close
511 approximation of a protocol Z39.50 Search Request - and Response PDUs
512 The <literal>setname</literal> is the resultSetName from the protocol.
513 You are required to establish a mapping between the set name and whatever
514 your backend database likes to use.
515 Similarly, the <literal>replace_set</literal> is a boolean value
516 corresponding to the resultSetIndicator field in the protocol.
517 <literal>num_bases/basenames</literal> is a length of/array of character
518 pointers to the database names provided by the client.
519 The <literal>query</literal> is the full query structure as defined in
520 the protocol ASN.1 specification.
521 It can be either of the possible query types, and it's up to you to
522 determine if you can handle the provided query type.
523 Rather than reproduce the C interface here, we'll refer you to the
524 structure definitions in the file
525 <filename>include/yaz/z-core.h</filename>. If you want to look at the
526 attributeSetId OID of the RPN query, you can either match it against
527 your own internal tables, or you can use the <link linkend="tools.oid">
532 The structure contains a number of hits, and an
533 <literal>errcode/errstring</literal> pair. If an error occurs
534 during the search, or if you're unhappy with the request, you should
535 set the errcode to a value from the BIB-1 diagnostic set. The value
536 will then be returned to the user in a nonsurrogate diagnostic record
537 in the response. The <literal>errstring</literal>, if provided, will
538 go in the addinfo field. Look at the protocol definition for the
539 defined error codes, and the suggested uses of the addinfo field.
543 The <function>bend_search</function> handler is also called when
544 the frontend server receives a SRU SearchRetrieveRequest.
545 For SRU, a CQL query is usually provided by the client.
546 The CQL query is available as part of <literal>Z_Query</literal>
547 structure (note that CQL is now part of Z39.50 via an external).
548 To support CQL in existing implementations that only do Type-1,
549 we refer to the CQL-to-PQF tool described
550 <link linkend="cql.to.pqf">here</link>.
554 To maintain backwards compatibility, the frontend server
555 of yaz always assume that error codes are BIB-1 diagnostics.
556 For SRU operation, a Bib-1 diagnostic code is mapped to
561 int (*bend_fetch) (void *handle, bend_fetch_rr *rr);
563 typedef struct bend_fetch_rr {
564 char *setname; /* set name */
565 int number; /* record number */
566 Z_ReferenceId *referenceId;/* reference ID */
567 Odr_oid *request_format; /* format, transfer syntax (OID) */
568 Z_RecordComposition *comp; /* Formatting instructions */
569 ODR stream; /* encoding stream - memory source if req */
570 ODR print; /* printing stream */
572 char *basename; /* name of database that provided record */
573 int len; /* length of record or -1 if structured */
574 char *record; /* record */
575 int last_in_set; /* is it? */
576 Odr_oid *output_format; /* response format/syntax (OID) */
577 int errcode; /* 0==success */
578 char *errstring; /* system error string or NULL */
579 int surrogate_flag; /* surrogate diagnostic */
580 char *schema; /* string record schema input/output */
585 The frontend server calls the <function>bend_fetch</function> handler
586 when it needs database records to fulfill a Z39.50 Search Request, a
587 Z39.50 Present Request or a SRU SearchRetrieveRequest.
588 The <literal>setname</literal> is simply the name of the result set
589 that holds the reference to the desired record.
590 The <literal>number</literal> is the offset into the set (with 1
591 being the first record in the set). The <literal>format</literal> field
592 is the record format requested by the client (See
593 <xref linkend="tools.oid"/>).
594 A value of NULL for <literal>format</literal> indicates that the
595 client did not request a specific format.
596 The <literal>stream</literal> argument is an &odr; stream which
597 should be used for allocating space for structured data records.
598 The stream will be reset when all records have been assembled, and
599 the response package has been transmitted.
600 For unstructured data, the backend is responsible for maintaining a
601 static or dynamic buffer for the record between calls.
605 If a SRU SearchRetrieveRequest is received by the frontend server,
606 the <literal>referenceId</literal> is NULL and the
607 <literal>format</literal> (transfer syntax) is the OID for XML.
608 The schema for SRU is stored in both the
609 <literal>Z_RecordComposition</literal>
610 structure and <literal>schema</literal> (simple string).
614 In the structure, the <literal>basename</literal> is the name of the
615 database that holds the
616 record. <literal>len</literal> is the length of the record returned, in
617 bytes, and <literal>record</literal> is a pointer to the record.
618 <literal>last_in_set</literal> should be nonzero only if the record
619 returned is the last one in the given result set.
620 <literal>errcode</literal> and <literal>errstring</literal>, if
621 given, will be interpreted as a global error pertaining to the
622 set, and will be returned in a non-surrogate-diagnostic.
623 If you wish to return the error as a surrogate-diagnostic
624 (local error) you can do this by setting
625 <literal>surrogate_flag</literal> to 1 also.
629 If the <literal>len</literal> field has the value -1, then
630 <literal>record</literal> is assumed to point to a constructed data
631 type. The <literal>format</literal> field will be used to determine
632 which encoder should be used to serialize the data.
637 If your backend generates structured records, it should use
638 <function>odr_malloc()</function> on the provided stream for allocating
639 data: This allows the frontend server to keep track of the record sizes.
644 The <literal>format</literal> field is mapped to an object identifier
645 in the direct reference of the resulting EXTERNAL representation
651 The current version of &yaz; only supports the direct reference mode.
656 int (*bend_present) (void *handle, bend_present_rr *rr);
659 char *setname; /* set name */
661 int number; /* record number */
662 Odr_oid *format; /* format, transfer syntax (OID) */
663 Z_ReferenceId *referenceId;/* reference ID */
664 Z_RecordComposition *comp; /* Formatting instructions */
665 ODR stream; /* encoding stream - memory source if required */
666 ODR print; /* printing stream */
667 bend_request request;
668 bend_association association;
670 int hits; /* number of hits */
671 int errcode; /* 0==OK */
672 char *errstring; /* system error string or NULL */
677 The <function>bend_present</function> handler is called when
678 the server receives a Z39.50 Present Request.
679 The <literal>setname</literal>,
680 <literal>start</literal> and <literal>number</literal> is the
681 name of the result set - start position - and number of records to
682 be retrieved respectively. <literal>format</literal> and
683 <literal>comp</literal> is the preferred transfer syntax and element
684 specifications of the present request.
687 Note that this is handler serves as a supplement for
688 <function>bend_fetch</function> and need not to be defined in order to
689 support search - and retrieve.
694 <sect2 id="server.delete"><title>Delete</title>
697 For back-ends that supports delete of a result set only one handler
702 int (*bend_delete)(void *handle, bend_delete_rr *rr);
704 typedef struct bend_delete_rr {
708 Z_ReferenceId *referenceId;
709 int delete_status; /* status for the whole operation */
710 int *statuses; /* status each set - indexed as setnames */
718 The delete set function definition is rather primitive, mostly because
719 we have had no practical need for it as of yet. If someone wants
720 to provide a full delete service, we'd be happy to add the
721 extra parameters that are required. Are there clients out there
722 that will actually delete sets they no longer need?
728 <sect2 id="server.scan"><title>Scan</title>
731 For servers that wish to offer the scan service one handler
736 int (*bend_scan)(void *handle, bend_scan_rr *rr);
739 BEND_SCAN_SUCCESS, /* ok */
740 BEND_SCAN_PARTIAL /* not all entries could be found */
743 typedef struct bend_scan_rr {
744 int num_bases; /* number of elements in databaselist */
745 char **basenames; /* databases to search */
746 Odr_oid *attributeset;
747 Z_ReferenceId *referenceId; /* reference ID */
748 Z_AttributesPlusTerm *term;
749 ODR stream; /* encoding stream - memory source if required */
750 ODR print; /* printing stream */
752 int *step_size; /* step size */
753 int term_position; /* desired index of term in result list/returned */
754 int num_entries; /* number of entries requested/returned */
756 /* scan term entries. The called handler does not have
757 to allocate this. Size of entries is num_entries (see above) */
758 struct scan_entry *entries;
759 bend_scan_status status;
762 char *scanClause; /* CQL scan clause */
763 char *setname; /* Scan in result set (NULL if omitted) */
767 This backend server handles both Z39.50 scan
768 and SRU scan. In order for a handler to distinguish between SRU (CQL) scan
769 Z39.50 Scan , it must check for a non-NULL value of
770 <literal>scanClause</literal>.
774 if designed today, it would be a choice using a union or similar,
775 but that would break binary compatibility with existing servers.
781 <sect1 id="server.invocation"><title>Application Invocation</title>
784 The finished application has the following
785 invocation syntax (by way of <function>statserv_main()</function>):
798 A listener specification consists of a transport mode followed by a
799 colon (:) followed by a listener address. The transport mode is
800 either <literal>tcp</literal>, <literal>unix:</literal> or
801 <literal>ssl</literal>.
805 For TCP and SSL, an address has the form
809 hostname | IP-number [: portnumber]
813 The port number defaults to 210 (standard Z39.50 port).
817 For UNIX, the address is the filename of socket.
821 For TCP/IP and SSL, the special hostnames <literal>@</literal> and
822 <literal>@6</literal> are mapped to the addresses
823 <literal>INADDR_ANY</literal> (IPV4) and
824 <literal>IN6ADDR_ANY_INIT</literal> (IPV6)
828 <example id="server.example.running.unix"><title>Running the GFS on Unix</title>
830 Assuming the server application <replaceable>appname</replaceable> is
831 started as root, the following will make it listen on port 210.
832 The server will change identity to <literal>nobody</literal>
833 and write its log to <filename>/var/log/app.log</filename>.
835 application -l /var/log/app.log -u nobody tcp:@:210
839 The server will accept Z39.50 requests and offer SRU service on port 210.
842 <example id="server.example.apache.sru"><title>Setting up Apache as SRU Frontend</title>
844 If you use <ulink url="&url.apache;">Apache</ulink>
845 as your public web server and want to offer HTTP port 80
846 access to the YAZ server on 210, you can use the
847 <ulink url="&url.apache.directive.proxypass;">
848 <literal>ProxyPass</literal></ulink>
850 If you have virtual host
851 <literal>srw.mydomain</literal> you can use the following directives
852 in Apache's httpd.conf:
855 ErrorLog /home/srw/logs/error_log
856 TransferLog /home/srw/logs/access_log
857 ProxyPass / http://srw.mydomain:210/
862 The above for the Apache 1.3 series.
865 <example id="server.example.local.access">
866 <title>Running a server with local access only</title>
868 Servers that is only being accessed from the local host should listen
869 on UNIX file socket rather than a Internet socket. To listen on
870 <filename>/tmp/mysocket</filename> start the server as follows:
872 application unix:/tmp/mysocket
877 <sect1 id="server.vhosts"><title>GFS Configuration and Virtual Hosts</title>
882 <!-- Keep this comment at the end of the file
887 sgml-minimize-attributes:nil
888 sgml-always-quote-attributes:t
891 sgml-parent-document: "yaz.xml"
892 sgml-local-catalogs: nil
893 sgml-namecase-general:t