Change license for proxy to GPL.
Add packages libyazproxy, libyazproxy-dev, yazproxy.
-Copyright (c) 1999-2004, Index Data and Mike Taylor.
+Copyright (c) 1998-2004, Index Data and Mike Taylor.
Permission to use, copy, modify, distribute, and sell this software and
its documentation, in whole or in part, for any purpose, is hereby granted,
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
AUTOMAKE_OPTIONS = foreign
-SUBDIRS = src include zlint zoom etc doc
+SUBDIRS = src include proxy zlint zoom etc doc
aclocaldir=$(datadir)/aclocal
aclocal_DATA = yazpp.m4
-EXTRA_DIST= LICENSE TODO yaz++-config.in yazpp.m4
+EXTRA_DIST= LICENSE LICENSE.proxy TODO yaz++-config.in yazpp.m4
dist-hook:
cp -R $(srcdir)/win $(distdir)
+--- 0.7.13 2004/03/30 Internal release.
+
+Move proxy to separate sub directory and change license to GPL.
+
--- 0.7.12 2004/03/17 Internal release.
Force libXSLT to reports errors to log file (similar to libXML2).
YAZ++ - A C++ library for YAZ
-$Id: README,v 1.1 2004-03-29 20:00:07 adam Exp $
+$Id: README,v 1.2 2004-03-29 22:46:50 adam Exp $
Introduction
Directory structure of the YAZ++ package:
- -- src (C++ library and proxy source)
+ -- src (C++ library)
-- zoom (C++ source for ZOOM)
+ -- proxy (C++ source for proxy)
-- include/yaz++ (C++ headers)
+ -- include/yaz++/proxy (C++ headers for proxy)
-- lib (compiled libraries)
-- win (Windows build files)
-- doc (DocBook-format documentation)
AC_INIT(configure.in)
-AM_INIT_AUTOMAKE("yaz++",0.7.12)
+AM_INIT_AUTOMAKE("yaz++",0.7.13)
AC_PROG_CC
AC_PROG_CPP
AC_MSG_CHECKING(for libXSLT)
if test -x $xsltdir/bin/xslt-config; then
XSLT_LIBS=`$xsltdir/bin/xslt-config --libs`
- LIBS="$XSLT_LIBS $LIBS"
XSLT_CFLAGS=`$xsltdir/bin/xslt-config --cflags`
XSLT_VER=`$xsltdir/bin/xslt-config --version`
AC_MSG_RESULT($XSLT_VER)
src/Makefile
include/Makefile
include/yaz++/Makefile
+ include/yaz++/proxy/Makefile
+ proxy/Makefile
zlint/Makefile
yaz++-config
zoom/Makefile
+yaz++ (0.7.13-1) unstable; urgency=low
+
+ * Upstream.
+
+ -- Adam Dickmeiss <adam@indexdata.dk> Mon, 29 Mar 2004 23:39:01 +0200
+
yaz++ (0.7.9-1) unstable; urgency=low
* Upstream.
Package: libyaz++-dev
Section: devel
Architecture: any
-Depends: libyaz++ (= ${Source-Version}), libxml2-dev, libxslt-dev, libyaz-dev
+Depends: libyaz++ (= ${Source-Version}), libyaz-dev
Description: YAZ++ library for Z39.50 applications in C++.
YAZ++ is a C++ library with an object oriented interface to YAZ and ZOOM.
Architecture: all
Description: Documentation for YAZ++.
YAZ++ is a C++ library with an object oriented interface to YAZ and ZOOM.
+
+Package: libyazproxy
+Section: libs
+Architecture: any
+Depends: ${shlibs:Depends}, libyaz++ (= ${Source-Version})
+Description: YAZ Proxy.
+ Libraries for YAZ proxy.
+
+Package: libyazproxy-dev
+Section: devel
+Architecture: any
+Depends: libyazproxy (= ${Source-Version}), libyaz++-dev (= ${Source-Version}), libxml2-dev, libxslt-dev
+Description: YAZ Proxy.
+ Development libraries for YAZ proxy.
+
+Package: yazproxy
+Section: utils
+Architecture: any
+Depends: libyazproxy (= ${Source-Version})
+Description: YAZ Proxy.
+ Powerful Proxy that converts Z39.50/SRW/SRU to Z39.50.
-debian/tmp/usr/include/yaz++/*
-debian/tmp/usr/lib/lib*.a
-debian/tmp/usr/lib/lib*.so
-debian/tmp/usr/lib/lib*.la
+debian/tmp/usr/include/yaz++/*.h
+debian/tmp/usr/lib/libyazcpp*.a
+debian/tmp/usr/lib/libzoomcpp*.a
+debian/tmp/usr/lib/libyazcpp.so
+debian/tmp/usr/lib/libzoomcpp.so
+debian/tmp/usr/lib/libyazcpp.la
+debian/tmp/usr/lib/libzoomcpp.la
debian/tmp/usr/bin/yaz++-config
debian/tmp/usr/share/aclocal/yazpp.m4
-debian/tmp/usr/lib/lib*.so.*
+debian/tmp/usr/lib/libyazcpp*.so.*
+debian/tmp/usr/lib/libzoomcpp*.so.*
dh_testdir
dh_testroot
cp LICENSE debian/copyright
- dh_installdocs -A README.txt
- dh_installchangelogs ChangeLog
+ dh_installdocs -A README LICENSE.proxy
+ dh_installchangelogs NEWS
dh_installdocs
dh_installexamples
mv debian/tmp/usr/share/doc/yaz++ debian/tmp/usr/share/doc/yaz++-doc
dh_fixperms
# dh_perl
# dh_python
- dh_makeshlibs -V 'libyaz++ (>= 0.7.8)'
+ dh_makeshlibs -V 'libyaz++ (>= 0.7.13)'
dh_installdeb
- dh_shlibdeps -l debian/libyaz++/usr/lib
+ dh_shlibdeps -L libyaz++ -l debian/libyaz++/usr/lib -L libyazproxy -l debian/libyazproxy/usr/lib
dh_gencontrol
dh_md5sums
dh_builddeb
-debian/tmp/usr/bin/yaz-proxy
-debian/tmp/usr/bin/zlint
-debian/tmp/usr/share/man/man8/yaz-proxy.8
+SUBDIRS = proxy
+
pkginclude_HEADERS = \
ir-assoc.h \
pdu-assoc.h \
pdu-observer.h \
- proxy.h \
query.h \
socket-manager.h \
socket-observer.h \
z-assoc.h \
z-query.h \
z-server.h \
- z-databases.h
+ z-databases.h \
+ record-cache.h \
+ cql2rpn.h
--- /dev/null
+/*
+ * Copyright (c) 1998-2004, Index Data.
+ * See the file LICENSE for details.
+ *
+ * $Id: cql2rpn.h,v 1.1 2004-03-29 22:46:50 adam Exp $
+ */
+
+#include <yaz/cql.h>
+#include <yaz/z-core.h>
+
+class YAZ_EXPORT Yaz_cql2rpn {
+ public:
+ Yaz_cql2rpn();
+ ~Yaz_cql2rpn();
+ void set_pqf_file(const char *fname);
+ int query_transform(const char *cql, Z_RPNQuery **rpnquery, ODR o,
+ char **addinfop);
+ private:
+ cql_transform_t m_transform;
+};
+
+++ /dev/null
-/*
- * Copyright (c) 1998-2004, Index Data.
- * See the file LICENSE for details.
- *
- * $Id: proxy.h,v 1.41 2004-02-27 00:42:57 adam Exp $
- */
-
-#include <sys/time.h>
-#include <yaz++/z-assoc.h>
-#include <yaz++/z-query.h>
-#include <yaz++/z-databases.h>
-#include <yaz/cql.h>
-#if HAVE_XSLT
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxslt/xsltutils.h>
-#include <libxslt/transform.h>
-#endif
-
-class Yaz_Proxy;
-
-#define MAX_ZURL_PLEX 10
-
-#define PROXY_LOG_APDU_CLIENT 1
-#define PROXY_LOG_APDU_SERVER 2
-#define PROXY_LOG_REQ_CLIENT 4
-#define PROXY_LOG_REQ_SERVER 8
-
-struct Yaz_RecordCache_Entry;
-
-class YAZ_EXPORT Yaz_ProxyConfig {
-public:
- Yaz_ProxyConfig();
- ~Yaz_ProxyConfig();
- int read_xml(const char *fname);
-
- int get_target_no(int no,
- const char **name,
- const char **url,
- int *limit_bw,
- int *limit_pdu,
- int *limit_req,
- int *target_idletime,
- int *client_idletime,
- int *max_clients,
- int *keepalive_limit_bw,
- int *keepalive_limit_pdu,
- int *pre_init,
- const char **cql2rpn);
-
- void get_generic_info(int *log_mask, int *max_clients);
-
- void get_target_info(const char *name, const char **url,
- int *limit_bw, int *limit_pdu, int *limit_req,
- int *target_idletime, int *client_idletime,
- int *max_clients,
- int *keepalive_limit_bw, int *keepalive_limit_pdu,
- int *pre_init,
- const char **cql2rpn);
-
- int check_query(ODR odr, const char *name, Z_Query *query, char **addinfo);
- int check_syntax(ODR odr, const char *name,
- Odr_oid *syntax, Z_RecordComposition *comp,
- char **addinfo, char **stylesheet, char **schema);
- char *get_explain(ODR odr, const char *name, const char *db,
- int *len);
-private:
- void operator=(const Yaz_ProxyConfig &conf);
- int mycmp(const char *hay, const char *item, size_t len);
-#if HAVE_XSLT
- int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
- const char *schema_identifier);
- xmlDocPtr m_docPtr;
- xmlNodePtr m_proxyPtr;
- void return_target_info(xmlNodePtr ptr, const char **url,
- int *limit_bw, int *limit_pdu, int *limit_req,
- int *target_idletime, int *client_idletime,
- int *keepalive_limit_bw, int *keepalive_limit_pdu,
- int *pre_init, const char **cql2rpn);
- void return_limit(xmlNodePtr ptr,
- int *limit_bw, int *limit_pdu, int *limit_req);
- int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
- char **addinfo);
- xmlNodePtr find_target_node(const char *name, const char *db);
- xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
- const char *get_text(xmlNodePtr ptr);
- int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
- Z_AttributeList *attrs,
- char **addinfo);
- int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
- char **addinfo);
-#endif
- int m_copy;
- int match_list(int v, const char *m);
- int atoi_l(const char **cp);
-};
-
-class YAZ_EXPORT Yaz_RecordCache {
- public:
- Yaz_RecordCache ();
- ~Yaz_RecordCache ();
- void add (ODR o, Z_NamePlusRecordList *npr, int start, int hits);
-
- int lookup (ODR o, Z_NamePlusRecordList **npr, int start, int num,
- Odr_oid *syntax, Z_RecordComposition *comp);
- void clear();
-
- void copy_searchRequest(Z_SearchRequest *sr);
- void copy_presentRequest(Z_PresentRequest *pr);
- void set_max_size(int sz);
- private:
- NMEM m_mem;
- Yaz_RecordCache_Entry *m_entries;
- Z_SearchRequest *m_searchRequest;
- Z_PresentRequest *m_presentRequest;
- int match (Yaz_RecordCache_Entry *entry,
- Odr_oid *syntax, int offset,
- Z_RecordComposition *comp);
- int m_max_size;
-};
-
-class YAZ_EXPORT Yaz_bw {
- public:
- Yaz_bw(int sz);
- ~Yaz_bw();
- void add_bytes(int m);
- int get_total();
- private:
- long m_sec; // time of most recent bucket
- int *m_bucket;
- int m_ptr;
- int m_size;
-};
-
-/// Private class
-class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc {
- friend class Yaz_Proxy;
- Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
- Yaz_Proxy *parent);
- ~Yaz_ProxyClient();
- void recv_GDU(Z_GDU *apdu, int len);
- void recv_Z_PDU(Z_APDU *apdu, int len);
- void recv_HTTP_response(Z_HTTP_Response *apdu, int len);
- IYaz_PDU_Observer* sessionNotify
- (IYaz_PDU_Observable *the_PDU_Observable, int fd);
- void shutdown();
- Yaz_Proxy *m_server;
- void failNotify();
- void timeoutNotify();
- void connectNotify();
- int send_to_target(Z_APDU *apdu);
- const char *get_session_str();
- char *m_cookie;
- Yaz_ProxyClient *m_next;
- Yaz_ProxyClient **m_prev;
- int m_init_flag;
- Yaz_Z_Query *m_last_query;
- Yaz_Z_Databases m_last_databases;
- char *m_last_resultSetId;
- int m_last_ok;
- int m_last_resultCount;
- int m_sr_transform;
- int m_seqno;
- int m_waiting;
- int m_resultSetStartPoint;
- int m_bytes_sent;
- int m_bytes_recv;
- int m_pdu_recv;
- ODR m_init_odr;
- Z_APDU *m_initResponse;
- Z_Options *m_initResponse_options;
- Z_ProtocolVersion *m_initResponse_version;
- int m_initResponse_preferredMessageSize;
- int m_initResponse_maximumRecordSize;
- Yaz_RecordCache m_cache;
- void pre_init_client();
- int m_target_idletime;
- Yaz_Proxy *m_root;
-};
-
-class YAZ_EXPORT Yaz_cql2rpn {
- public:
- Yaz_cql2rpn();
- ~Yaz_cql2rpn();
- void set_pqf_file(const char *fname);
- int query_transform(const char *cql, Z_RPNQuery **rpnquery, ODR o,
- char **addinfop);
- private:
- cql_transform_t m_transform;
-};
-
-
-/// Information Retrieval Proxy Server.
-class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
- private:
- char *get_cookie(Z_OtherInformation **otherInfo);
- char *get_proxy(Z_OtherInformation **otherInfo);
- Yaz_ProxyClient *get_client(Z_APDU *apdu, const char *cookie,
- const char *proxy_host);
- Z_APDU *result_set_optimize(Z_APDU *apdu);
- void shutdown();
-
- Yaz_ProxyClient *m_client;
- IYaz_PDU_Observable *m_PDU_Observable;
- Yaz_ProxyClient *m_clientPool;
- Yaz_Proxy *m_parent;
- int m_seqno;
- int m_max_clients;
- int m_log_mask;
- int m_keepalive_limit_bw;
- int m_keepalive_limit_pdu;
- int m_client_idletime;
- int m_target_idletime;
- char *m_proxyTarget;
- char *m_default_target;
- char *m_proxy_authentication;
- long m_seed;
- char *m_optimize;
- int m_session_no; // sequence for each client session
- char m_session_str[30]; // session string (time:session_no)
- Yaz_ProxyConfig *m_config;
- char *m_config_fname;
- int m_bytes_sent;
- int m_bytes_recv;
- int m_bw_max;
- Yaz_bw m_bw_stat;
- int m_pdu_max;
- Yaz_bw m_pdu_stat;
- Z_GDU *m_bw_hold_PDU;
- int m_max_record_retrieve;
- void handle_max_record_retrieve(Z_APDU *apdu);
- void display_diagrecs(Z_DiagRec **pp, int num);
- Z_Records *create_nonSurrogateDiagnostics(ODR o, int error,
- const char *addinfo);
-
- Z_APDU *handle_query_validation(Z_APDU *apdu);
- Z_APDU *handle_query_transformation(Z_APDU *apdu);
-
- Z_APDU *handle_syntax_validation(Z_APDU *apdu);
- const char *load_balance(const char **url);
- int m_reconfig_flag;
- Yaz_ProxyConfig *check_reconfigure();
- int m_request_no;
- int m_invalid_session;
- int m_marcxml_flag;
- xsltStylesheetPtr m_stylesheet_xsp;
- int m_stylesheet_offset;
- Z_APDU *m_stylesheet_apdu;
- Z_NamePlusRecordList *m_stylesheet_nprl;
- char *m_schema;
- void convert_to_marcxml(Z_NamePlusRecordList *p);
- int convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu);
- void convert_xsl_delay();
- Z_APDU *m_initRequest_apdu;
- int m_initRequest_preferredMessageSize;
- int m_initRequest_maximumRecordSize;
- Z_Options *m_initRequest_options;
- Z_ProtocolVersion *m_initRequest_version;
- NMEM m_initRequest_mem;
- Z_APDU *m_apdu_invalid_session;
- NMEM m_mem_invalid_session;
- int send_PDU_convert(Z_APDU *apdu);
- ODR m_s2z_odr_init;
- ODR m_s2z_odr_search;
- int m_s2z_hit_count;
- int m_s2z_packing;
- char *m_s2z_database;
- Z_APDU *m_s2z_init_apdu;
- Z_APDU *m_s2z_search_apdu;
- Z_APDU *m_s2z_present_apdu;
- char *m_s2z_stylesheet;
- char *m_soap_ns;
- int send_to_srw_client_error(int error, const char *add);
- int send_to_srw_client_ok(int hits, Z_Records *records, int start);
- int send_http_response(int code);
- int send_srw_response(Z_SRW_PDU *srw_pdu);
- int send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
- int num_diagnostics);
- int z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
- Z_DefaultDiagFormat *ddf);
- int m_http_keepalive;
- const char *m_http_version;
- Yaz_cql2rpn m_cql2rpn;
- struct timeval m_time_tv;
- void logtime();
- Z_ElementSetNames *mk_esn_from_schema(ODR o, const char *schema);
- Z_ReferenceId *m_referenceId;
- NMEM m_referenceId_mem;
-#define NO_SPARE_SOLARIS_FD 10
- int m_lo_fd[NO_SPARE_SOLARIS_FD];
- void low_socket_open();
- void low_socket_close();
- public:
- Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
- Yaz_Proxy *parent = 0);
- ~Yaz_Proxy();
- void inc_request_no();
- void recv_GDU(Z_GDU *apdu, int len);
- void handle_incoming_HTTP(Z_HTTP_Request *req);
- void handle_incoming_Z_PDU(Z_APDU *apdu);
- IYaz_PDU_Observer* sessionNotify
- (IYaz_PDU_Observable *the_PDU_Observable, int fd);
- void failNotify();
- void timeoutNotify();
- void connectNotify();
- void markInvalid();
- const char *option(const char *name, const char *value);
- void set_default_target(const char *target);
- void set_proxy_authentication (const char *auth);
- char *get_proxy_target() { return m_proxyTarget; };
- char *get_session_str() { return m_session_str; };
- void set_max_clients(int m) { m_max_clients = m; };
- void set_client_idletime (int t) { m_client_idletime = (t > 1) ? t : 600; };
- void set_target_idletime (int t) { m_target_idletime = (t > 1) ? t : 600; };
- int get_target_idletime () { return m_target_idletime; }
- int set_config(const char *name);
- void reconfig() { m_reconfig_flag = 1; }
- int send_to_client(Z_APDU *apdu);
- int server(const char *addr);
- void pre_init();
- int get_log_mask() { return m_log_mask; };
- int handle_init_response_for_invalid_session(Z_APDU *apdu);
-};
-
--- /dev/null
+
+proxyincludedir=$(pkgincludedir)/proxy
+
+proxyinclude_HEADERS = proxy.h bw.h
--- /dev/null
+/* $Id: bw.h,v 1.1 2004-03-29 22:46:50 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+class YAZ_EXPORT Yaz_bw {
+ public:
+ Yaz_bw(int sz);
+ ~Yaz_bw();
+ void add_bytes(int m);
+ int get_total();
+ private:
+ long m_sec; // time of most recent bucket
+ int *m_bucket;
+ int m_ptr;
+ int m_size;
+};
+
--- /dev/null
+/* $Id: proxy.h,v 1.1 2004-03-29 22:46:50 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <sys/time.h>
+#include <yaz++/z-assoc.h>
+#include <yaz++/z-query.h>
+#include <yaz++/z-databases.h>
+#include <yaz++/cql2rpn.h>
+#include <yaz/cql.h>
+#include <yaz++/proxy/bw.h>
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+#endif
+
+class Yaz_Proxy;
+
+#define MAX_ZURL_PLEX 10
+
+#define PROXY_LOG_APDU_CLIENT 1
+#define PROXY_LOG_APDU_SERVER 2
+#define PROXY_LOG_REQ_CLIENT 4
+#define PROXY_LOG_REQ_SERVER 8
+
+struct Yaz_RecordCache_Entry;
+
+class YAZ_EXPORT Yaz_ProxyConfig {
+public:
+ Yaz_ProxyConfig();
+ ~Yaz_ProxyConfig();
+ int read_xml(const char *fname);
+
+ int get_target_no(int no,
+ const char **name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn);
+
+ void get_generic_info(int *log_mask, int *max_clients);
+
+ void get_target_info(const char *name, const char **url,
+ int *limit_bw, int *limit_pdu, int *limit_req,
+ int *target_idletime, int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw, int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn);
+
+ int check_query(ODR odr, const char *name, Z_Query *query, char **addinfo);
+ int check_syntax(ODR odr, const char *name,
+ Odr_oid *syntax, Z_RecordComposition *comp,
+ char **addinfo, char **stylesheet, char **schema);
+ char *get_explain(ODR odr, const char *name, const char *db,
+ int *len);
+private:
+ void operator=(const Yaz_ProxyConfig &conf);
+ int mycmp(const char *hay, const char *item, size_t len);
+#if HAVE_XSLT
+ int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
+ const char *schema_identifier);
+ xmlDocPtr m_docPtr;
+ xmlNodePtr m_proxyPtr;
+ void return_target_info(xmlNodePtr ptr, const char **url,
+ int *limit_bw, int *limit_pdu, int *limit_req,
+ int *target_idletime, int *client_idletime,
+ int *keepalive_limit_bw, int *keepalive_limit_pdu,
+ int *pre_init, const char **cql2rpn);
+ void return_limit(xmlNodePtr ptr,
+ int *limit_bw, int *limit_pdu, int *limit_req);
+ int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+ char **addinfo);
+ xmlNodePtr find_target_node(const char *name, const char *db);
+ xmlNodePtr find_target_db(xmlNodePtr ptr, const char *db);
+ const char *get_text(xmlNodePtr ptr);
+ int check_type_1_attributes(ODR odr, xmlNodePtr ptr,
+ Z_AttributeList *attrs,
+ char **addinfo);
+ int check_type_1_structure(ODR odr, xmlNodePtr ptr, Z_RPNStructure *q,
+ char **addinfo);
+#endif
+ int m_copy;
+ int match_list(int v, const char *m);
+ int atoi_l(const char **cp);
+};
+
+class YAZ_EXPORT Yaz_RecordCache {
+ public:
+ Yaz_RecordCache ();
+ ~Yaz_RecordCache ();
+ void add (ODR o, Z_NamePlusRecordList *npr, int start, int hits);
+
+ int lookup (ODR o, Z_NamePlusRecordList **npr, int start, int num,
+ Odr_oid *syntax, Z_RecordComposition *comp);
+ void clear();
+
+ void copy_searchRequest(Z_SearchRequest *sr);
+ void copy_presentRequest(Z_PresentRequest *pr);
+ void set_max_size(int sz);
+ private:
+ NMEM m_mem;
+ Yaz_RecordCache_Entry *m_entries;
+ Z_SearchRequest *m_searchRequest;
+ Z_PresentRequest *m_presentRequest;
+ int match (Yaz_RecordCache_Entry *entry,
+ Odr_oid *syntax, int offset,
+ Z_RecordComposition *comp);
+ int m_max_size;
+};
+
+/// Private class
+class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc {
+ friend class Yaz_Proxy;
+ Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent);
+ ~Yaz_ProxyClient();
+ void recv_GDU(Z_GDU *apdu, int len);
+ void recv_Z_PDU(Z_APDU *apdu, int len);
+ void recv_HTTP_response(Z_HTTP_Response *apdu, int len);
+ IYaz_PDU_Observer* sessionNotify
+ (IYaz_PDU_Observable *the_PDU_Observable, int fd);
+ void shutdown();
+ Yaz_Proxy *m_server;
+ void failNotify();
+ void timeoutNotify();
+ void connectNotify();
+ int send_to_target(Z_APDU *apdu);
+ const char *get_session_str();
+ char *m_cookie;
+ Yaz_ProxyClient *m_next;
+ Yaz_ProxyClient **m_prev;
+ int m_init_flag;
+ Yaz_Z_Query *m_last_query;
+ Yaz_Z_Databases m_last_databases;
+ char *m_last_resultSetId;
+ int m_last_ok;
+ int m_last_resultCount;
+ int m_sr_transform;
+ int m_seqno;
+ int m_waiting;
+ int m_resultSetStartPoint;
+ int m_bytes_sent;
+ int m_bytes_recv;
+ int m_pdu_recv;
+ ODR m_init_odr;
+ Z_APDU *m_initResponse;
+ Z_Options *m_initResponse_options;
+ Z_ProtocolVersion *m_initResponse_version;
+ int m_initResponse_preferredMessageSize;
+ int m_initResponse_maximumRecordSize;
+ Yaz_RecordCache m_cache;
+ void pre_init_client();
+ int m_target_idletime;
+ Yaz_Proxy *m_root;
+};
+
+
+/// Information Retrieval Proxy Server.
+class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc {
+ private:
+ char *get_cookie(Z_OtherInformation **otherInfo);
+ char *get_proxy(Z_OtherInformation **otherInfo);
+ Yaz_ProxyClient *get_client(Z_APDU *apdu, const char *cookie,
+ const char *proxy_host);
+ Z_APDU *result_set_optimize(Z_APDU *apdu);
+ void shutdown();
+
+ Yaz_ProxyClient *m_client;
+ IYaz_PDU_Observable *m_PDU_Observable;
+ Yaz_ProxyClient *m_clientPool;
+ Yaz_Proxy *m_parent;
+ int m_seqno;
+ int m_max_clients;
+ int m_log_mask;
+ int m_keepalive_limit_bw;
+ int m_keepalive_limit_pdu;
+ int m_client_idletime;
+ int m_target_idletime;
+ char *m_proxyTarget;
+ char *m_default_target;
+ char *m_proxy_authentication;
+ long m_seed;
+ char *m_optimize;
+ int m_session_no; // sequence for each client session
+ char m_session_str[30]; // session string (time:session_no)
+ Yaz_ProxyConfig *m_config;
+ char *m_config_fname;
+ int m_bytes_sent;
+ int m_bytes_recv;
+ int m_bw_max;
+ Yaz_bw m_bw_stat;
+ int m_pdu_max;
+ Yaz_bw m_pdu_stat;
+ Z_GDU *m_bw_hold_PDU;
+ int m_max_record_retrieve;
+ void handle_max_record_retrieve(Z_APDU *apdu);
+ void display_diagrecs(Z_DiagRec **pp, int num);
+ Z_Records *create_nonSurrogateDiagnostics(ODR o, int error,
+ const char *addinfo);
+
+ Z_APDU *handle_query_validation(Z_APDU *apdu);
+ Z_APDU *handle_query_transformation(Z_APDU *apdu);
+
+ Z_APDU *handle_syntax_validation(Z_APDU *apdu);
+ const char *load_balance(const char **url);
+ int m_reconfig_flag;
+ Yaz_ProxyConfig *check_reconfigure();
+ int m_request_no;
+ int m_invalid_session;
+ int m_marcxml_flag;
+ xsltStylesheetPtr m_stylesheet_xsp;
+ int m_stylesheet_offset;
+ Z_APDU *m_stylesheet_apdu;
+ Z_NamePlusRecordList *m_stylesheet_nprl;
+ char *m_schema;
+ void convert_to_marcxml(Z_NamePlusRecordList *p);
+ int convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu);
+ void convert_xsl_delay();
+ Z_APDU *m_initRequest_apdu;
+ int m_initRequest_preferredMessageSize;
+ int m_initRequest_maximumRecordSize;
+ Z_Options *m_initRequest_options;
+ Z_ProtocolVersion *m_initRequest_version;
+ NMEM m_initRequest_mem;
+ Z_APDU *m_apdu_invalid_session;
+ NMEM m_mem_invalid_session;
+ int send_PDU_convert(Z_APDU *apdu);
+ ODR m_s2z_odr_init;
+ ODR m_s2z_odr_search;
+ int m_s2z_hit_count;
+ int m_s2z_packing;
+ char *m_s2z_database;
+ Z_APDU *m_s2z_init_apdu;
+ Z_APDU *m_s2z_search_apdu;
+ Z_APDU *m_s2z_present_apdu;
+ char *m_s2z_stylesheet;
+ char *m_soap_ns;
+ int send_to_srw_client_error(int error, const char *add);
+ int send_to_srw_client_ok(int hits, Z_Records *records, int start);
+ int send_http_response(int code);
+ int send_srw_response(Z_SRW_PDU *srw_pdu);
+ int send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+ int num_diagnostics);
+ int z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
+ Z_DefaultDiagFormat *ddf);
+ int m_http_keepalive;
+ const char *m_http_version;
+ Yaz_cql2rpn m_cql2rpn;
+ struct timeval m_time_tv;
+ void logtime();
+ Z_ElementSetNames *mk_esn_from_schema(ODR o, const char *schema);
+ Z_ReferenceId *m_referenceId;
+ NMEM m_referenceId_mem;
+#define NO_SPARE_SOLARIS_FD 10
+ int m_lo_fd[NO_SPARE_SOLARIS_FD];
+ void low_socket_open();
+ void low_socket_close();
+ public:
+ Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent = 0);
+ ~Yaz_Proxy();
+ void inc_request_no();
+ void recv_GDU(Z_GDU *apdu, int len);
+ void handle_incoming_HTTP(Z_HTTP_Request *req);
+ void handle_incoming_Z_PDU(Z_APDU *apdu);
+ IYaz_PDU_Observer* sessionNotify
+ (IYaz_PDU_Observable *the_PDU_Observable, int fd);
+ void failNotify();
+ void timeoutNotify();
+ void connectNotify();
+ void markInvalid();
+ const char *option(const char *name, const char *value);
+ void set_default_target(const char *target);
+ void set_proxy_authentication (const char *auth);
+ char *get_proxy_target() { return m_proxyTarget; };
+ char *get_session_str() { return m_session_str; };
+ void set_max_clients(int m) { m_max_clients = m; };
+ void set_client_idletime (int t) { m_client_idletime = (t > 1) ? t : 600; };
+ void set_target_idletime (int t) { m_target_idletime = (t > 1) ? t : 600; };
+ int get_target_idletime () { return m_target_idletime; }
+ int set_config(const char *name);
+ void reconfig() { m_reconfig_flag = 1; }
+ int send_to_client(Z_APDU *apdu);
+ int server(const char *addr);
+ void pre_init();
+ int get_log_mask() { return m_log_mask; };
+ int handle_init_response_for_invalid_session(Z_APDU *apdu);
+};
+
--- /dev/null
+/*
+ * Copyright (c) 2002-2004, Index Data.
+ * See the file LICENSE for details.
+ *
+ * $Id: record-cache.h,v 1.1 2004-03-29 22:46:50 adam Exp $
+ */
+
+
+#include <yaz/nmem.h>
+#include <yaz/z-core.h>
+
+class Yaz_RecordCache_Entry;
+
+class YAZ_EXPORT Yaz_RecordCache {
+ public:
+ Yaz_RecordCache ();
+ ~Yaz_RecordCache ();
+ void add (ODR o, Z_NamePlusRecordList *npr, int start, int hits);
+
+ int lookup (ODR o, Z_NamePlusRecordList **npr, int start, int num,
+ Odr_oid *syntax, Z_RecordComposition *comp);
+ void clear();
+
+ void copy_searchRequest(Z_SearchRequest *sr);
+ void copy_presentRequest(Z_PresentRequest *pr);
+ void set_max_size(int sz);
+ private:
+ NMEM m_mem;
+ Yaz_RecordCache_Entry *m_entries;
+ Z_SearchRequest *m_searchRequest;
+ Z_PresentRequest *m_presentRequest;
+ int match (Yaz_RecordCache_Entry *entry,
+ Odr_oid *syntax, int offset,
+ Z_RecordComposition *comp);
+ int m_max_size;
+};
--- /dev/null
+## $Id: Makefile.am,v 1.1 2004-03-29 22:46:51 adam Exp $
+
+AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include $(XSLT_CFLAGS)
+
+lib_LTLIBRARIES = libyazproxy.la
+libyazproxy_la_LDFLAGS=-version-info 1:0:0
+
+libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp
+
+bin_PROGRAMS = yaz-proxy
+
+yaz_proxy_SOURCES=yaz-proxy-main.cpp
+
+LDADD=libyazproxy.la ../src/libyazcpp.la $(YAZLALIB) $(XSLT_LIBS)
+libyazproxy_la_LIBADD = $(XSLT_LIBS)
--- /dev/null
+/* $Id: yaz-bw.cpp,v 1.1 2004-03-29 22:46:51 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <time.h>
+#include <yaz/log.h>
+#include <yaz++/proxy/bw.h>
+
+Yaz_bw::Yaz_bw(int sz)
+{
+ m_sec = 0;
+ m_size = sz;
+ m_bucket = new int[m_size];
+ m_ptr = 0;
+}
+
+Yaz_bw::~Yaz_bw()
+{
+ delete [] m_bucket;
+}
+
+int Yaz_bw::get_total()
+{
+ add_bytes(0);
+ int bw = 0;
+ int i;
+ for (i = 0; i<m_size; i++)
+ bw += m_bucket[i];
+ return bw;
+}
+
+void Yaz_bw::add_bytes(int b)
+{
+ long now = time(0);
+
+ int d = now - m_sec;
+ if (d > m_size)
+ d = m_size;
+ while (--d >= 0)
+ {
+ if (++m_ptr == m_size)
+ m_ptr = 0;
+ m_bucket[m_ptr] = 0;
+ }
+ m_bucket[m_ptr] += b;
+ m_sec = now;
+}
+
--- /dev/null
+/* $Id: yaz-proxy-config.cpp,v 1.1 2004-03-29 22:46:51 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <ctype.h>
+#include <yaz/log.h>
+#include <yaz++/proxy/proxy.h>
+
+Yaz_ProxyConfig::Yaz_ProxyConfig()
+{
+ m_copy = 0;
+#if HAVE_XSLT
+ m_docPtr = 0;
+ m_proxyPtr = 0;
+#endif
+}
+
+Yaz_ProxyConfig::~Yaz_ProxyConfig()
+{
+#if HAVE_XSLT
+ if (!m_copy && m_docPtr)
+ xmlFreeDoc(m_docPtr);
+#endif
+}
+
+int Yaz_ProxyConfig::read_xml(const char *fname)
+{
+#if HAVE_XSLT
+ xmlDocPtr ndoc = xmlParseFile(fname);
+
+ if (!ndoc)
+ {
+ yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
+ return -1; // no good
+ }
+ xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
+ if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
+ strcmp((const char *) proxyPtr->name, "proxy"))
+ {
+ yaz_log(LOG_WARN, "No proxy element in %s", fname);
+ xmlFreeDoc(ndoc);
+ return -1;
+ }
+ m_proxyPtr = proxyPtr;
+
+ // OK: release previous and make it the current one.
+ if (m_docPtr)
+ xmlFreeDoc(m_docPtr);
+ m_docPtr = ndoc;
+ return 0;
+#else
+ return -2;
+#endif
+}
+
+#if HAVE_XSLT
+const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
+{
+ for(ptr = ptr->children; ptr; ptr = ptr->next)
+ if (ptr->type == XML_TEXT_NODE)
+ {
+ xmlChar *t = ptr->content;
+ if (t)
+ {
+ while (*t == ' ')
+ t++;
+ return (const char *) t;
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req)
+{
+ for (ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "bandwidth"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_bw = atoi(t);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "retrieve"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_req = atoi(t);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "pdu"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *limit_pdu = atoi(t);
+ }
+ }
+}
+#endif
+
+#if HAVE_XSLT
+void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+ *pre_init = 0;
+ int no_url = 0;
+ ptr = ptr->children;
+ for (; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "preinit"))
+ {
+ const char *v = get_text(ptr);
+ *pre_init = v ? atoi(v) : 1;
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "url"))
+ {
+ const char *t = get_text(ptr);
+ if (t && no_url < MAX_ZURL_PLEX)
+ {
+ url[no_url++] = t;
+ url[no_url] = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "keepalive"))
+ {
+ int dummy;
+ *keepalive_limit_bw = 500000;
+ *keepalive_limit_pdu = 1000;
+ return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
+ &dummy);
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "limit"))
+ return_limit(ptr, limit_bw, limit_pdu, limit_req);
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "target-timeout"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *target_idletime = atoi(t);
+ if (*target_idletime < 0)
+ *target_idletime = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "client-timeout"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *client_idletime = atoi(t);
+ if (*client_idletime < 0)
+ *client_idletime = 0;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "cql2rpn"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ *cql2rpn = t;
+ }
+ }
+}
+#endif
+
+int Yaz_ProxyConfig::atoi_l(const char **cp)
+{
+ int v = 0;
+ while (**cp && isdigit(**cp))
+ {
+ v = v*10 + (**cp - '0');
+ (*cp)++;
+ }
+ return v;
+}
+
+int Yaz_ProxyConfig::match_list(int v, const char *m)
+{
+ while(m && *m)
+ {
+ while(*m && isspace(*m))
+ m++;
+ if (*m == '*')
+ return 1;
+ int l = atoi_l(&m);
+ int h = l;
+ if (*m == '-')
+ {
+ ++m;
+ h = atoi_l(&m);
+ }
+ if (v >= l && v <= h)
+ return 1;
+ if (*m == ',')
+ m++;
+ }
+ return 0;
+}
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
+ Z_AttributeList *attrs,
+ char **addinfo)
+{
+ int i;
+ for (i = 0; i<attrs->num_attributes; i++)
+ {
+ Z_AttributeElement *el = attrs->attributes[i];
+
+ if (!el->attributeType)
+ continue;
+ int type = *el->attributeType;
+ int *value = 0;
+
+ if (el->which == Z_AttributeValue_numeric && el->value.numeric)
+ value = el->value.numeric;
+
+ xmlNodePtr ptr;
+ for(ptr = ptrl->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "attribute"))
+ {
+ const char *match_type = 0;
+ const char *match_value = 0;
+ const char *match_error = 0;
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_type = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "value") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_value = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "error") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_error = (const char *) attr->children->content;
+ }
+ if (match_type && match_value)
+ {
+ char addinfo_str[20];
+ if (!match_list(type, match_type))
+ continue;
+
+ *addinfo_str = '\0';
+ if (!strcmp(match_type, "*"))
+ sprintf (addinfo_str, "%d", type);
+ else if (value)
+ {
+ if (!match_list(*value, match_value))
+ continue;
+ sprintf (addinfo_str, "%d", *value);
+ }
+ else
+ continue;
+
+ if (match_error)
+ {
+ if (*addinfo_str)
+ *addinfo = odr_strdup(odr, addinfo_str);
+ return atoi(match_error);
+ }
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
+ Z_RPNStructure *q,
+ char **addinfo)
+{
+ if (q->which == Z_RPNStructure_complex)
+ {
+ int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
+ if (e)
+ return e;
+ e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
+ return e;
+ }
+ else if (q->which == Z_RPNStructure_simple)
+ {
+ if (q->u.simple->which == Z_Operand_APT)
+ {
+ return check_type_1_attributes(
+ odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
+ addinfo);
+ }
+ }
+ return 0;
+}
+#endif
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
+ char **addinfo)
+{
+ // possibly check for Bib-1
+ return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
+}
+#endif
+
+int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
+ char **addinfo)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+
+ ptr = find_target_node(name, 0);
+ if (ptr)
+ {
+ if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
+ return check_type_1(odr, ptr, query->u.type_1, addinfo);
+ }
+#endif
+ return 0;
+}
+
+#if HAVE_XSLT
+int Yaz_ProxyConfig::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
+ const char *schema_identifier)
+{
+ char *esn = 0;
+ int default_match = 1;
+ if (comp && comp->which == Z_RecordComp_simple &&
+ comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
+ {
+ esn = comp->u.simple->u.generic;
+ }
+ // if no ESN/schema was given accept..
+ if (!esn)
+ return 1;
+ // check if schema identifier match
+ if (schema_identifier && !strcmp(esn, schema_identifier))
+ return 1;
+ // Check each name element
+ for (; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "name"))
+ {
+ xmlNodePtr tptr = ptr->children;
+ default_match = 0;
+ for (; tptr; tptr = tptr->next)
+ if (tptr->type == XML_TEXT_NODE && tptr->content)
+ {
+ xmlChar *t = tptr->content;
+ while (*t && isspace(*t))
+ t++;
+ int i = 0;
+ while (esn[i] && esn[i] == t[i])
+ i++;
+ if (!esn[i] && (!t[i] || isspace(t[i])))
+ return 1;
+ }
+ }
+ }
+ return default_match;
+}
+#endif
+
+int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
+ Odr_oid *syntax, Z_RecordComposition *comp,
+ char **addinfo,
+ char **stylesheet, char **schema)
+{
+ if (stylesheet)
+ {
+ xfree (*stylesheet);
+ *stylesheet = 0;
+ }
+ if (schema)
+ {
+ xfree (*schema);
+ *schema = 0;
+ }
+#if HAVE_XSLT
+ int syntax_has_matched = 0;
+ xmlNodePtr ptr;
+
+ ptr = find_target_node(name, 0);
+ if (!ptr)
+ return 0;
+ for(ptr = ptr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "syntax"))
+ {
+ int match = 0; // if we match record syntax
+ const char *match_type = 0;
+ const char *match_error = 0;
+ const char *match_marcxml = 0;
+ const char *match_stylesheet = 0;
+ const char *match_identifier = 0;
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ {
+ if (!strcmp((const char *) attr->name, "type") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_type = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "error") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_error = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "marcxml") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_marcxml = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "stylesheet") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_stylesheet = (const char *) attr->children->content;
+ if (!strcmp((const char *) attr->name, "identifier") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ match_identifier = (const char *) attr->children->content;
+ }
+ if (match_type)
+ {
+ if (!strcmp(match_type, "*"))
+ match = 1;
+ else if (!strcmp(match_type, "none"))
+ {
+ if (syntax == 0)
+ match = 1;
+ }
+ else if (syntax)
+ {
+ int match_oid[OID_SIZE];
+ oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
+ if (oid_oidcmp(match_oid, syntax) == 0)
+ match = 1;
+ }
+ }
+ if (match)
+ {
+ if (!match_error)
+ syntax_has_matched = 1;
+ match = check_schema(ptr->children, comp, match_identifier);
+ }
+ if (match)
+ {
+ if (stylesheet && match_stylesheet)
+ {
+ xfree(*stylesheet);
+ *stylesheet = xstrdup(match_stylesheet);
+ }
+ if (schema && match_identifier)
+ {
+ xfree(*schema);
+ *schema = xstrdup(match_identifier);
+ }
+ if (match_marcxml)
+ {
+ return -1;
+ }
+ if (match_error)
+ {
+ if (syntax_has_matched) // if syntax OK, bad schema/ESN
+ return 25;
+ if (syntax)
+ {
+ char dotoid_str[100];
+ oid_to_dotstring(syntax, dotoid_str);
+ *addinfo = odr_strdup(odr, dotoid_str);
+ }
+ return atoi(match_error);
+ }
+ return 0;
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+#if HAVE_XSLT
+xmlNodePtr Yaz_ProxyConfig::find_target_db(xmlNodePtr ptr, const char *db)
+{
+ xmlNodePtr dptr;
+ if (!db)
+ return ptr;
+ if (!ptr)
+ return 0;
+ for (dptr = ptr->children; dptr; dptr = dptr->next)
+ if (dptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) dptr->name, "database"))
+ {
+ struct _xmlAttr *attr;
+ for (attr = dptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content
+ && (!strcmp((const char *) attr->children->content, db)
+ || !strcmp((const char *) attr->children->content,
+ "*")))
+ return dptr;
+ }
+ }
+ return ptr;
+}
+
+xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name, const char *db)
+{
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "target"))
+ {
+ // default one ?
+ if (!name)
+ {
+ // <target default="1"> ?
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "default") &&
+ attr->children && attr->children->type == XML_TEXT_NODE)
+ {
+ xmlChar *t = attr->children->content;
+ if (!t || *t == '1')
+ {
+ return find_target_db(ptr, db);
+ }
+ }
+ }
+ else
+ {
+ // <target name="name"> ?
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content
+ && (!strcmp((const char *) attr->children->content,
+ name)
+ || !strcmp((const char *) attr->children->content,
+ "*")))
+ {
+ return find_target_db(ptr, db);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+int Yaz_ProxyConfig::get_target_no(int no,
+ const char **name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return 0;
+ int i = 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "target"))
+ {
+ if (i == no)
+ {
+ struct _xmlAttr *attr;
+ for (attr = ptr->properties; attr; attr = attr->next)
+ if (!strcmp((const char *) attr->name, "name"))
+ {
+ if (attr->children
+ && attr->children->type==XML_TEXT_NODE
+ && attr->children->content)
+ *name = (const char *) attr->children->content;
+ }
+ return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
+ target_idletime, client_idletime,
+ keepalive_limit_bw, keepalive_limit_pdu,
+ pre_init, cql2rpn);
+ return 1;
+ }
+ i++;
+ }
+#endif
+ return 0;
+}
+
+int Yaz_ProxyConfig::mycmp(const char *hay, const char *item, size_t len)
+{
+ if (len == strlen(item) && memcmp(hay, item, len) == 0)
+ return 1;
+ return 0;
+}
+
+void Yaz_ProxyConfig::get_generic_info(int *log_mask,
+ int *max_clients)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ return;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE
+ && !strcmp((const char *) ptr->name, "log"))
+ {
+ const char *v = get_text(ptr);
+ *log_mask = 0;
+ while (v && *v)
+ {
+ const char *cp = v;
+ while (*cp && *cp != ',' && !isspace(*cp))
+ cp++;
+ size_t len = cp - v;
+ if (mycmp(v, "client-apdu", len))
+ *log_mask |= PROXY_LOG_APDU_CLIENT;
+ if (mycmp(v, "server-apdu", len))
+ *log_mask |= PROXY_LOG_APDU_SERVER;
+ if (mycmp(v, "client-requests", len))
+ *log_mask |= PROXY_LOG_REQ_CLIENT;
+ if (mycmp(v, "server-requests", len))
+ *log_mask |= PROXY_LOG_REQ_SERVER;
+ if (isdigit(*v))
+ *log_mask |= atoi(v);
+ if (*cp == ',')
+ cp++;
+ while (*cp && isspace(*cp))
+ cp++;
+ v = cp;
+ }
+ }
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "max-clients"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *max_clients = atoi(t);
+ if (*max_clients < 1)
+ *max_clients = 1;
+ }
+ }
+ }
+#endif
+}
+
+char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
+ int *len)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr = find_target_node(name, db);
+ if (ptr)
+ {
+ ptr = ptr->children;
+ for (; ptr; ptr = ptr->next)
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "explain"))
+ {
+ xmlNodePtr ptr1 = ptr->children;
+ if (db)
+ {
+ for (; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr1->name, "serverInfo"))
+ break;
+ if (!ptr1)
+ continue;
+ for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr1->name, "database"))
+ break;
+
+ if (!ptr1)
+ continue;
+ for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
+ if (ptr1->type == XML_TEXT_NODE &&
+ ptr1->content &&
+ !strcmp((const char *) ptr1->content, db))
+ break;
+ if (!ptr1)
+ continue;
+ }
+ xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
+
+ xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
+
+ xmlDocSetRootElement(doc, ptr2);
+
+ xmlChar *buf_out;
+ xmlDocDumpMemory(doc, &buf_out, len);
+ char *content = (char*) odr_malloc(odr, *len);
+ memcpy(content, buf_out, *len);
+
+ xmlFree(buf_out);
+ xmlFreeDoc(doc);
+ return content;
+ }
+ }
+#endif
+ return 0;
+}
+
+void Yaz_ProxyConfig::get_target_info(const char *name,
+ const char **url,
+ int *limit_bw,
+ int *limit_pdu,
+ int *limit_req,
+ int *target_idletime,
+ int *client_idletime,
+ int *max_clients,
+ int *keepalive_limit_bw,
+ int *keepalive_limit_pdu,
+ int *pre_init,
+ const char **cql2rpn)
+{
+#if HAVE_XSLT
+ xmlNodePtr ptr;
+ if (!m_proxyPtr)
+ {
+ url[0] = name;
+ url[1] = 0;
+ return;
+ }
+ url[0] = 0;
+ for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
+ {
+ if (ptr->type == XML_ELEMENT_NODE &&
+ !strcmp((const char *) ptr->name, "max-clients"))
+ {
+ const char *t = get_text(ptr);
+ if (t)
+ {
+ *max_clients = atoi(t);
+ if (*max_clients < 1)
+ *max_clients = 1;
+ }
+ }
+ }
+ ptr = find_target_node(name, 0);
+ if (ptr)
+ {
+ if (name)
+ {
+ url[0] = name;
+ url[1] = 0;
+ }
+ return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
+ target_idletime, client_idletime,
+ keepalive_limit_bw, keepalive_limit_pdu,
+ pre_init, cql2rpn);
+ }
+#else
+ *url = name;
+ return;
+#endif
+}
+
+
--- /dev/null
+/* $Id: yaz-proxy.cpp,v 1.1 2004-03-29 22:46:51 adam Exp $
+ Copyright (c) 1998-2004, Index Data.
+
+This file is part of the yaz-proxy.
+
+Zebra is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Zebra; see the file LICENSE.proxy. If not, write to the
+Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <yaz/srw.h>
+#include <yaz/marcdisp.h>
+#include <yaz/yaz-iconv.h>
+#include <yaz/log.h>
+#include <yaz/diagbib1.h>
+#include <yaz++/proxy/proxy.h>
+#include <yaz/pquery.h>
+
+static const char *apdu_name(Z_APDU *apdu)
+{
+ switch (apdu->which)
+ {
+ case Z_APDU_initRequest:
+ return "initRequest";
+ case Z_APDU_initResponse:
+ return "initResponse";
+ case Z_APDU_searchRequest:
+ return "searchRequest";
+ case Z_APDU_searchResponse:
+ return "searchResponse";
+ case Z_APDU_presentRequest:
+ return "presentRequest";
+ case Z_APDU_presentResponse:
+ return "presentResponse";
+ case Z_APDU_deleteResultSetRequest:
+ return "deleteResultSetRequest";
+ case Z_APDU_deleteResultSetResponse:
+ return "deleteResultSetResponse";
+ case Z_APDU_scanRequest:
+ return "scanRequest";
+ case Z_APDU_scanResponse:
+ return "scanResponse";
+ case Z_APDU_sortRequest:
+ return "sortRequest";
+ case Z_APDU_sortResponse:
+ return "sortResponse";
+ case Z_APDU_extendedServicesRequest:
+ return "extendedServicesRequest";
+ case Z_APDU_extendedServicesResponse:
+ return "extendedServicesResponse";
+ case Z_APDU_close:
+ return "close";
+ }
+ return "other";
+}
+
+static const char *gdu_name(Z_GDU *gdu)
+{
+ switch(gdu->which)
+ {
+ case Z_GDU_Z3950:
+ return apdu_name(gdu->u.z3950);
+ case Z_GDU_HTTP_Request:
+ return "HTTP Request";
+ case Z_GDU_HTTP_Response:
+ return "HTTP Response";
+ }
+ return "Unknown request/response";
+}
+
+Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent) :
+ Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
+{
+ m_PDU_Observable = the_PDU_Observable;
+ m_client = 0;
+ m_parent = parent;
+ m_clientPool = 0;
+ m_seqno = 1;
+ m_keepalive_limit_bw = 500000;
+ m_keepalive_limit_pdu = 1000;
+ m_proxyTarget = 0;
+ m_default_target = 0;
+ m_proxy_authentication = 0;
+ m_max_clients = 150;
+ m_log_mask = 0;
+ m_seed = time(0);
+ m_client_idletime = 600;
+ m_target_idletime = 600;
+ m_optimize = xstrdup ("1");
+ strcpy(m_session_str, "0 ");
+ m_session_no=0;
+ m_bytes_sent = 0;
+ m_bytes_recv = 0;
+ m_bw_hold_PDU = 0;
+ m_bw_max = 0;
+ m_pdu_max = 0;
+ m_max_record_retrieve = 0;
+ m_reconfig_flag = 0;
+ m_config_fname = 0;
+ m_request_no = 0;
+ m_invalid_session = 0;
+ m_referenceId = 0;
+ m_referenceId_mem = nmem_create();
+ m_config = 0;
+ m_marcxml_flag = 0;
+ m_stylesheet_xsp = 0;
+ m_stylesheet_nprl = 0;
+ m_s2z_stylesheet = 0;
+ m_s2z_database = 0;
+ m_schema = 0;
+ m_initRequest_apdu = 0;
+ m_initRequest_mem = 0;
+ m_initRequest_preferredMessageSize = 0;
+ m_initRequest_maximumRecordSize = 0;
+ m_initRequest_options = 0;
+ m_initRequest_version = 0;
+ m_apdu_invalid_session = 0;
+ m_mem_invalid_session = 0;
+ m_s2z_odr_init = 0;
+ m_s2z_odr_search = 0;
+ m_s2z_init_apdu = 0;
+ m_s2z_search_apdu = 0;
+ m_s2z_present_apdu = 0;
+ m_http_keepalive = 0;
+ m_http_version = 0;
+ m_soap_ns = 0;
+ m_s2z_packing = Z_SRW_recordPacking_string;
+ m_time_tv.tv_sec = 0;
+ m_time_tv.tv_usec = 0;
+ if (!m_parent)
+ low_socket_open();
+}
+
+Yaz_Proxy::~Yaz_Proxy()
+{
+ yaz_log(LOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
+ m_bytes_sent, m_bytes_recv);
+ nmem_destroy(m_initRequest_mem);
+ nmem_destroy(m_mem_invalid_session);
+ nmem_destroy(m_referenceId_mem);
+
+ xfree (m_proxyTarget);
+ xfree (m_default_target);
+ xfree (m_proxy_authentication);
+ xfree (m_optimize);
+
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+
+ xfree (m_schema);
+ if (m_s2z_odr_init)
+ odr_destroy(m_s2z_odr_init);
+ if (m_s2z_odr_search)
+ odr_destroy(m_s2z_odr_search);
+ if (!m_parent)
+ low_socket_close();
+ delete m_config;
+}
+
+int Yaz_Proxy::set_config(const char *config)
+{
+ delete m_config;
+ m_config = new Yaz_ProxyConfig();
+ xfree(m_config_fname);
+ m_config_fname = xstrdup(config);
+ int r = m_config->read_xml(config);
+ if (!r)
+ m_config->get_generic_info(&m_log_mask, &m_max_clients);
+ return r;
+}
+
+void Yaz_Proxy::set_default_target(const char *target)
+{
+ xfree (m_default_target);
+ m_default_target = 0;
+ if (target)
+ m_default_target = (char *) xstrdup (target);
+}
+
+void Yaz_Proxy::set_proxy_authentication (const char *auth)
+{
+ xfree (m_proxy_authentication);
+ m_proxy_authentication = 0;
+ if (auth)
+ m_proxy_authentication = (char *) xstrdup (auth);
+}
+
+Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
+{
+ if (m_parent)
+ return m_parent->check_reconfigure();
+
+ Yaz_ProxyConfig *cfg = m_config;
+ if (m_reconfig_flag)
+ {
+ yaz_log(LOG_LOG, "reconfigure");
+ yaz_log_reopen();
+ if (m_config_fname && cfg)
+ {
+ yaz_log(LOG_LOG, "reconfigure config %s", m_config_fname);
+ int r = cfg->read_xml(m_config_fname);
+ if (r)
+ yaz_log(LOG_WARN, "reconfigure failed");
+ else
+ {
+ m_log_mask = 0;
+ cfg->get_generic_info(&m_log_mask, &m_max_clients);
+ }
+ }
+ else
+ yaz_log(LOG_LOG, "reconfigure");
+ m_reconfig_flag = 0;
+ }
+ return cfg;
+}
+
+IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
+ *the_PDU_Observable, int fd)
+{
+ check_reconfigure();
+ Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable, this);
+ new_proxy->m_config = 0;
+ new_proxy->m_config_fname = 0;
+ new_proxy->timeout(m_client_idletime);
+ new_proxy->m_target_idletime = m_target_idletime;
+ new_proxy->set_default_target(m_default_target);
+ new_proxy->m_max_clients = m_max_clients;
+ new_proxy->m_log_mask = m_log_mask;
+ new_proxy->set_APDU_log(get_APDU_log());
+ if (m_log_mask & PROXY_LOG_APDU_CLIENT)
+ new_proxy->set_APDU_yazlog(1);
+ else
+ new_proxy->set_APDU_yazlog(0);
+ new_proxy->set_proxy_authentication(m_proxy_authentication);
+ sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
+ m_session_no++;
+ yaz_log (LOG_LOG, "%sNew session %s", new_proxy->m_session_str,
+ the_PDU_Observable->getpeername());
+ return new_proxy;
+}
+
+char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
+{
+ int oid[OID_SIZE];
+ Z_OtherInformationUnit *oi;
+ struct oident ent;
+ ent.proto = PROTO_Z3950;
+ ent.oclass = CLASS_USERINFO;
+ ent.value = (oid_value) VAL_COOKIE;
+ assert (oid_ent_to_oid (&ent, oid));
+
+ if (oid_ent_to_oid (&ent, oid) &&
+ (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
+ oi->which == Z_OtherInfo_characterInfo)
+ return oi->information.characterInfo;
+ return 0;
+}
+
+char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
+{
+ int oid[OID_SIZE];
+ Z_OtherInformationUnit *oi;
+ struct oident ent;
+ ent.proto = PROTO_Z3950;
+ ent.oclass = CLASS_USERINFO;
+ ent.value = (oid_value) VAL_PROXY;
+ if (oid_ent_to_oid (&ent, oid) &&
+ (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
+ oi->which == Z_OtherInfo_characterInfo)
+ return oi->information.characterInfo;
+ return 0;
+}
+
+const char *Yaz_Proxy::load_balance(const char **url)
+{
+ int zurl_in_use[MAX_ZURL_PLEX];
+ int zurl_in_spare[MAX_ZURL_PLEX];
+ Yaz_ProxyClient *c;
+ int i;
+
+ for (i = 0; i<MAX_ZURL_PLEX; i++)
+ {
+ zurl_in_use[i] = 0;
+ zurl_in_spare[i] = 0;
+ }
+ for (c = m_parent->m_clientPool; c; c = c->m_next)
+ {
+ for (i = 0; url[i]; i++)
+ if (!strcmp(url[i], c->get_hostname()))
+ {
+ zurl_in_use[i]++;
+ if (c->m_cookie == 0 && c->m_server == 0 && c->m_waiting == 0)
+ zurl_in_spare[i]++;
+ }
+ }
+ int min_use = 100000;
+ int spare_for_min = 0;
+ int max_spare = 0;
+ const char *ret_min = 0;
+ const char *ret_spare = 0;
+ for (i = 0; url[i]; i++)
+ {
+ yaz_log(LOG_DEBUG, "%szurl=%s use=%d spare=%d",
+ m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
+ if (min_use > zurl_in_use[i])
+ {
+ ret_min = url[i];
+ min_use = zurl_in_use[i];
+ spare_for_min = zurl_in_spare[i];
+ }
+ if (max_spare < zurl_in_spare[i])
+ {
+ ret_spare = url[i];
+ max_spare = zurl_in_spare[i];
+ }
+ }
+ // use the one with minimum connections if spare is > 3
+ if (spare_for_min > 3)
+ return ret_min;
+ // use one with most spares (if any)
+ if (max_spare > 0)
+ return ret_spare;
+ return ret_min;
+}
+
+Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
+ const char *proxy_host)
+{
+ assert (m_parent);
+ Yaz_Proxy *parent = m_parent;
+ Yaz_ProxyClient *c = m_client;
+
+ if (!m_proxyTarget)
+ {
+ const char *url[MAX_ZURL_PLEX];
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (proxy_host)
+ {
+#if 1
+/* only to be enabled for debugging... */
+ if (!strcmp(proxy_host, "stop"))
+ exit(0);
+#endif
+ xfree(m_default_target);
+ m_default_target = xstrdup(proxy_host);
+ proxy_host = m_default_target;
+ }
+ int client_idletime = -1;
+ const char *cql2rpn_fname = 0;
+ url[0] = m_default_target;
+ url[1] = 0;
+ if (cfg)
+ {
+ int pre_init = 0;
+ cfg->get_target_info(proxy_host, url, &m_bw_max,
+ &m_pdu_max, &m_max_record_retrieve,
+ &m_target_idletime, &client_idletime,
+ &parent->m_max_clients,
+ &m_keepalive_limit_bw,
+ &m_keepalive_limit_pdu,
+ &pre_init,
+ &cql2rpn_fname);
+ }
+ if (client_idletime != -1)
+ {
+ m_client_idletime = client_idletime;
+ timeout(m_client_idletime);
+ }
+ if (cql2rpn_fname)
+ m_cql2rpn.set_pqf_file(cql2rpn_fname);
+ if (!url[0])
+ {
+ yaz_log(LOG_LOG, "%sNo default target", m_session_str);
+ return 0;
+ }
+ // we don't handle multiplexing for cookie session, so we just
+ // pick the first one in this case (anonymous users will be able
+ // to use any backend)
+ if (cookie && *cookie)
+ m_proxyTarget = (char*) xstrdup(url[0]);
+ else
+ m_proxyTarget = (char*) xstrdup(load_balance(url));
+ }
+ if (cookie && *cookie)
+ { // search in sessions with a cookie
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ assert (c->m_prev);
+ assert (*c->m_prev == c);
+ if (c->m_cookie && !strcmp(cookie,c->m_cookie) &&
+ !strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ // Found it in cache
+ // The following handles "cancel"
+ // If connection is busy (waiting for PDU) and
+ // we have an initRequest we can safely do re-open
+ if (c->m_waiting && apdu->which == Z_APDU_initRequest)
+ {
+ yaz_log (LOG_LOG, "%s REOPEN target=%s", m_session_str,
+ c->get_hostname());
+ c->close();
+ c->m_init_flag = 0;
+
+ c->m_last_ok = 0;
+ c->m_cache.clear();
+ c->m_last_resultCount = 0;
+ c->m_sr_transform = 0;
+ c->m_waiting = 0;
+ c->m_resultSetStartPoint = 0;
+ c->m_target_idletime = m_target_idletime;
+ if (c->client(m_proxyTarget))
+ {
+ delete c;
+ return 0;
+ }
+ c->timeout(30);
+ }
+ c->m_seqno = parent->m_seqno;
+ if (c->m_server && c->m_server != this)
+ c->m_server->m_client = 0;
+ c->m_server = this;
+ (parent->m_seqno)++;
+ yaz_log (LOG_DEBUG, "get_client 1 %p %p", this, c);
+ return c;
+ }
+ }
+ }
+ else if (!c)
+ {
+ // don't have a client session yet. Search in session w/o cookie
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ assert (c->m_prev);
+ assert (*c->m_prev == c);
+ if (c->m_server == 0 && c->m_cookie == 0 &&
+ c->m_waiting == 0 &&
+ !strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ // found it in cache
+ yaz_log (LOG_LOG, "%sREUSE %d %s",
+ m_session_str, parent->m_seqno, c->get_hostname());
+
+ c->m_seqno = parent->m_seqno;
+ assert(c->m_server == 0);
+ c->m_server = this;
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ (parent->m_seqno)++;
+
+ parent->pre_init();
+
+ return c;
+ }
+ }
+ }
+ if (!m_client)
+ {
+ if (apdu->which != Z_APDU_initRequest)
+ {
+ yaz_log (LOG_LOG, "%sno init request as first PDU", m_session_str);
+ return 0;
+ }
+ Z_InitRequest *initRequest = apdu->u.initRequest;
+
+ if (!initRequest->idAuthentication)
+ {
+ if (m_proxy_authentication)
+ {
+ initRequest->idAuthentication =
+ (Z_IdAuthentication *)
+ odr_malloc (odr_encode(),
+ sizeof(*initRequest->idAuthentication));
+ initRequest->idAuthentication->which =
+ Z_IdAuthentication_open;
+ initRequest->idAuthentication->u.open =
+ odr_strdup (odr_encode(), m_proxy_authentication);
+ }
+ }
+ // go through list of clients - and find the lowest/oldest one.
+ Yaz_ProxyClient *c_min = 0;
+ int min_seq = -1;
+ int no_of_clients = 0;
+ if (parent->m_clientPool)
+ yaz_log (LOG_DEBUG, "Existing sessions");
+ for (c = parent->m_clientPool; c; c = c->m_next)
+ {
+ yaz_log (LOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
+ c->m_waiting, c->get_hostname(),
+ c->m_cookie ? c->m_cookie : "");
+ no_of_clients++;
+ if (min_seq < 0 || c->m_seqno < min_seq)
+ {
+ min_seq = c->m_seqno;
+ c_min = c;
+ }
+ }
+ if (no_of_clients >= parent->m_max_clients)
+ {
+ c = c_min;
+ if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
+ {
+ yaz_log (LOG_LOG, "%sMAXCLIENTS %d Destroy %d",
+ m_session_str, parent->m_max_clients, c->m_seqno);
+ if (c->m_server && c->m_server != this)
+ delete c->m_server;
+ c->m_server = 0;
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
+ m_session_str, parent->m_max_clients,
+ c->m_seqno, parent->m_seqno, c->get_hostname());
+ xfree (c->m_cookie);
+ c->m_cookie = 0;
+ if (cookie)
+ c->m_cookie = xstrdup(cookie);
+ c->m_seqno = parent->m_seqno;
+ if (c->m_server && c->m_server != this)
+ {
+ c->m_server->m_client = 0;
+ delete c->m_server;
+ }
+ (parent->m_seqno)++;
+ c->m_target_idletime = m_target_idletime;
+ c->timeout(m_target_idletime);
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ return c;
+ }
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sNEW %d %s",
+ m_session_str, parent->m_seqno, m_proxyTarget);
+ c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
+ c->m_next = parent->m_clientPool;
+ if (c->m_next)
+ c->m_next->m_prev = &c->m_next;
+ parent->m_clientPool = c;
+ c->m_prev = &parent->m_clientPool;
+ }
+
+ xfree (c->m_cookie);
+ c->m_cookie = 0;
+ if (cookie)
+ c->m_cookie = xstrdup(cookie);
+
+ c->m_seqno = parent->m_seqno;
+ c->m_init_flag = 0;
+ c->m_last_resultCount = 0;
+ c->m_last_ok = 0;
+ c->m_cache.clear();
+ c->m_sr_transform = 0;
+ c->m_waiting = 0;
+ c->m_resultSetStartPoint = 0;
+ (parent->m_seqno)++;
+ if (c->client(m_proxyTarget))
+ {
+ delete c;
+ return 0;
+ }
+ c->m_target_idletime = m_target_idletime;
+ c->timeout(30);
+
+ if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+ }
+ yaz_log (LOG_DEBUG, "get_client 3 %p %p", this, c);
+ return c;
+}
+
+void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
+{
+ int i;
+ for (i = 0; i<num; i++)
+ {
+ oident *ent;
+ Z_DefaultDiagFormat *r;
+ Z_DiagRec *p = pp[i];
+ if (p->which != Z_DiagRec_defaultFormat)
+ {
+ yaz_log(LOG_LOG, "%sError no diagnostics", m_session_str);
+ return;
+ }
+ else
+ r = p->u.defaultFormat;
+ if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
+ ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
+ yaz_log(LOG_LOG, "%sError unknown diagnostic set", m_session_str);
+ switch (r->which)
+ {
+ case Z_DefaultDiagFormat_v2Addinfo:
+ yaz_log(LOG_LOG, "%sError %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v2Addinfo);
+ break;
+ case Z_DefaultDiagFormat_v3Addinfo:
+ yaz_log(LOG_LOG, "%sError %d %s:%s",
+ m_session_str,
+ *r->condition, diagbib1_str(*r->condition),
+ r->u.v3Addinfo);
+ break;
+ }
+ }
+}
+
+int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
+{
+ if (!m_stylesheet_xsp || p->num_records <= 0)
+ return 0; /* no XSLT to be done ... */
+
+ m_stylesheet_offset = 0;
+ m_stylesheet_nprl = p;
+ m_stylesheet_apdu = apdu;
+ timeout(0);
+ return 1;
+}
+
+void Yaz_Proxy::convert_xsl_delay()
+{
+ Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
+ if (npr->which == Z_NamePlusRecord_databaseRecord)
+ {
+ Z_External *r = npr->u.databaseRecord;
+ if (r->which == Z_External_octet)
+ {
+#if 0
+ fwrite((char*) r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, stdout);
+#endif
+ xmlDocPtr res, doc = xmlParseMemory(
+ (char*) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len);
+
+
+ yaz_log(LOG_LOG, "%sXSLT convert %d",
+ m_session_str, m_stylesheet_offset);
+ res = xsltApplyStylesheet(m_stylesheet_xsp, doc, 0);
+
+ if (res)
+ {
+ xmlChar *out_buf;
+ int out_len;
+ xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
+
+ m_stylesheet_nprl->records[m_stylesheet_offset]->
+ u.databaseRecord =
+ z_ext_record(odr_encode(), VAL_TEXT_XML,
+ (char*) out_buf, out_len);
+ xmlFree(out_buf);
+ xmlFreeDoc(res);
+ }
+
+ xmlFreeDoc(doc);
+ }
+ }
+ m_stylesheet_offset++;
+ if (m_stylesheet_offset == m_stylesheet_nprl->num_records)
+ {
+ m_stylesheet_nprl = 0;
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+ m_stylesheet_xsp = 0;
+ timeout(m_client_idletime);
+ send_PDU_convert(m_stylesheet_apdu);
+ }
+ else
+ timeout(0);
+}
+
+void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p)
+{
+ int i;
+
+ yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC-8");
+ yaz_marc_t mt = yaz_marc_create();
+ yaz_marc_xml(mt, YAZ_MARC_MARCXML);
+ yaz_marc_iconv(mt, cd);
+ for (i = 0; i < p->num_records; i++)
+ {
+ Z_NamePlusRecord *npr = p->records[i];
+ if (npr->which == Z_NamePlusRecord_databaseRecord)
+ {
+ Z_External *r = npr->u.databaseRecord;
+ if (r->which == Z_External_octet)
+ {
+ int rlen;
+ char *result;
+ if (yaz_marc_decode_buf(mt, (char*) r->u.octet_aligned->buf,
+ r->u.octet_aligned->len,
+ &result, &rlen))
+ {
+ npr->u.databaseRecord = z_ext_record(odr_encode(),
+ VAL_TEXT_XML,
+ result, rlen);
+ }
+ }
+ }
+ }
+ if (cd)
+ yaz_iconv_close(cd);
+ yaz_marc_destroy(mt);
+}
+
+void Yaz_Proxy::logtime()
+{
+ if (m_time_tv.tv_sec)
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ long diff = (tv.tv_sec - m_time_tv.tv_sec)*1000000 +
+ (tv.tv_usec - m_time_tv.tv_usec);
+ if (diff >= 0)
+ yaz_log(LOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
+ diff/1000000, (diff/1000)%1000);
+ }
+ m_time_tv.tv_sec = 0;
+ m_time_tv.tv_usec = 0;
+}
+
+int Yaz_Proxy::send_http_response(int code)
+{
+ ODR o = odr_encode();
+ Z_GDU *gdu = z_get_HTTP_Response(o, code);
+ Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+ if (m_http_version)
+ hres->version = odr_strdup(o, m_http_version);
+ if (m_http_keepalive)
+ z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+ else
+ timeout(0);
+
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ {
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ gdu_name(gdu));
+ }
+ int len;
+ int r = send_GDU(gdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+}
+
+int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
+{
+ ODR o = odr_encode();
+ const char *ctype = "text/xml";
+ Z_GDU *gdu = z_get_HTTP_Response(o, 200);
+ Z_HTTP_Response *hres = gdu->u.HTTP_Response;
+ if (m_http_version)
+ hres->version = odr_strdup(o, m_http_version);
+ z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
+ if (m_http_keepalive)
+ z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
+ else
+ timeout(0);
+
+ static Z_SOAP_Handler soap_handlers[2] = {
+#if HAVE_XSLT
+ {"http://www.loc.gov/zing/srw/", 0,
+ (Z_SOAP_fun) yaz_srw_codec},
+#endif
+ {0, 0, 0}
+ };
+
+ Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP));
+ soap_package->which = Z_SOAP_generic;
+ soap_package->u.generic =
+ (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic));
+ soap_package->u.generic->no = 0;
+ soap_package->u.generic->ns = soap_handlers[0].ns;
+ soap_package->u.generic->p = (void *) srw_pdu;
+ soap_package->ns = m_soap_ns;
+ z_soap_codec_enc_xsl(o, &soap_package,
+ &hres->content_buf, &hres->content_len,
+ soap_handlers, 0, m_s2z_stylesheet);
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ {
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ gdu_name(gdu));
+ }
+ int len;
+ int r = send_GDU(gdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+}
+
+int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
+{
+ ODR o = odr_encode();
+ Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->num_diagnostics = 1;
+ srw_res->diagnostics = (Z_SRW_diagnostic *)
+ odr_malloc(o, sizeof(*srw_res->diagnostics));
+ yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add);
+ return send_srw_response(srw_pdu);
+}
+
+int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
+ Z_DefaultDiagFormat *ddf)
+{
+ int bib1_code = *ddf->condition;
+ if (bib1_code == 109)
+ return 404;
+ srw_res->num_diagnostics = 1;
+ srw_res->diagnostics = (Z_SRW_diagnostic *)
+ odr_malloc(o, sizeof(*srw_res->diagnostics));
+ yaz_mk_std_diagnostic(o, srw_res->diagnostics,
+ yaz_diag_bib1_to_srw(*ddf->condition),
+ ddf->u.v2Addinfo);
+ return 0;
+}
+
+int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
+{
+ ODR o = odr_encode();
+ Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->numberOfRecords = odr_intdup (o, hits);
+ if (records && records->which == Z_Records_DBOSD)
+ {
+ srw_res->num_records =
+ records->u.databaseOrSurDiagnostics->num_records;
+ int i;
+ srw_res->records = (Z_SRW_record *)
+ odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record));
+ for (i = 0; i < srw_res->num_records; i++)
+ {
+ Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i];
+ if (npr->which != Z_NamePlusRecord_databaseRecord)
+ {
+ srw_res->records[i].recordSchema = "diagnostic";
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = "67";
+ srw_res->records[i].recordData_len = 2;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ continue;
+ }
+ Z_External *r = npr->u.databaseRecord;
+ oident *ent = oid_getentbyoid(r->direct_reference);
+ if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML)
+ {
+ srw_res->records[i].recordSchema = m_schema;
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = (char*)
+ r->u.octet_aligned->buf;
+ srw_res->records[i].recordData_len = r->u.octet_aligned->len;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ }
+ else
+ {
+ srw_res->records[i].recordSchema = "diagnostic";
+ srw_res->records[i].recordPacking = m_s2z_packing;
+ srw_res->records[i].recordData_buf = "67";
+ srw_res->records[i].recordData_len = 2;
+ srw_res->records[i].recordPosition = odr_intdup(o, i+start);
+ }
+ }
+ }
+ if (records && records->which == Z_Records_NSD)
+ {
+ int http_code;
+ http_code = z_to_srw_diag(odr_encode(), srw_res,
+ records->u.nonSurrogateDiagnostic);
+ if (http_code)
+ return send_http_response(http_code);
+ }
+ return send_srw_response(srw_pdu);
+
+}
+
+int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
+ int num_diagnostics)
+{
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (cfg)
+ {
+ int len;
+ char *b = cfg->get_explain(odr_encode(), 0 /* target */,
+ m_s2z_database, &len);
+ if (b)
+ {
+ Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
+ Z_SRW_explainResponse *er = res->u.explain_response;
+
+ er->record.recordData_buf = b;
+ er->record.recordData_len = len;
+ er->record.recordPacking = m_s2z_packing;
+ er->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
+
+ er->diagnostics = diagnostics;
+ er->num_diagnostics = num_diagnostics;
+ return send_srw_response(res);
+ }
+ }
+ return send_http_response(404);
+}
+
+int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
+{
+ if (m_http_version)
+ {
+ if (apdu->which == Z_APDU_initResponse)
+ {
+ Z_InitResponse *res = apdu->u.initResponse;
+ if (*res->result == 0)
+ {
+ send_to_srw_client_error(3, 0);
+ }
+ else if (!m_s2z_search_apdu)
+ {
+ send_srw_explain_response(0, 0);
+ }
+ else
+ {
+ handle_incoming_Z_PDU(m_s2z_search_apdu);
+ }
+ }
+ else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
+ {
+ m_s2z_search_apdu = 0;
+ Z_SearchResponse *res = apdu->u.searchResponse;
+ m_s2z_hit_count = *res->resultCount;
+ if (res->records && res->records->which == Z_Records_NSD)
+ {
+ send_to_srw_client_ok(0, res->records, 1);
+ }
+ else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
+ {
+ // adjust
+ Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
+
+ if (*pr->resultSetStartPoint <= m_s2z_hit_count)
+ {
+ if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
+ > m_s2z_hit_count)
+ *pr->numberOfRecordsRequested =
+ 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
+ }
+ handle_incoming_Z_PDU(m_s2z_present_apdu);
+ }
+ else
+ {
+ m_s2z_present_apdu = 0;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
+ }
+ }
+ else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
+ {
+ int start =
+ *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
+
+ m_s2z_present_apdu = 0;
+ Z_PresentResponse *res = apdu->u.presentResponse;
+ send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
+ }
+ }
+ else
+ {
+ int len = 0;
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
+ apdu_name(apdu));
+ int r = send_Z_PDU(apdu, &len);
+ m_bytes_sent += len;
+ m_bw_stat.add_bytes(len);
+ logtime();
+ return r;
+ }
+ return 0;
+}
+
+int Yaz_Proxy::send_to_client(Z_APDU *apdu)
+{
+ int kill_session = 0;
+ Z_ReferenceId **new_id = get_referenceIdP(apdu);
+
+ if (new_id)
+ *new_id = m_referenceId;
+
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+
+ *sr->searchStatus = 0;
+ display_diagrecs(&dr_p, 1);
+ }
+ else
+ {
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_marcxml_flag)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+
+ }
+ if (sr->resultCount)
+ {
+ yaz_log(LOG_LOG, "%s%d hits", m_session_str,
+ *sr->resultCount);
+ if (*sr->resultCount < 0)
+ {
+ m_invalid_session = 1;
+ kill_session = 1;
+
+ *sr->searchStatus = 0;
+ sr->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
+ *sr->resultCount = 0;
+ }
+ }
+ }
+ }
+ else if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *sr = apdu->u.presentResponse;
+ Z_Records *p = sr->records;
+ if (p && p->which == Z_Records_NSD)
+ {
+ Z_DiagRec dr, *dr_p = &dr;
+ dr.which = Z_DiagRec_defaultFormat;
+ dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+ if (*sr->presentStatus == Z_PresentStatus_success)
+ *sr->presentStatus = Z_PresentStatus_failure;
+ display_diagrecs(&dr_p, 1);
+ }
+ if (p && p->which == Z_Records_DBOSD)
+ {
+ if (m_marcxml_flag)
+ convert_to_marcxml(p->u.databaseOrSurDiagnostics);
+ if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
+ return 0;
+ }
+ }
+ else if (apdu->which == Z_APDU_initResponse)
+ {
+ if (m_initRequest_options)
+ {
+ Z_Options *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<24; i++)
+ if (ODR_MASK_GET(m_initRequest_options, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->options, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->options = nopt;
+ }
+ if (m_initRequest_version)
+ {
+ Z_ProtocolVersion *nopt =
+ (Odr_bitmask *)odr_malloc(odr_encode(),
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(nopt);
+
+ int i;
+ for (i = 0; i<8; i++)
+ if (ODR_MASK_GET(m_initRequest_version, i) &&
+ ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
+ ODR_MASK_SET(nopt, i);
+ apdu->u.initResponse->protocolVersion = nopt;
+ }
+ apdu->u.initResponse->preferredMessageSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_preferredMessageSize >
+ m_initRequest_preferredMessageSize ?
+ m_initRequest_preferredMessageSize :
+ m_client->m_initResponse_preferredMessageSize);
+ apdu->u.initResponse->maximumRecordSize =
+ odr_intdup(odr_encode(),
+ m_client->m_initResponse_maximumRecordSize >
+ m_initRequest_maximumRecordSize ?
+ m_initRequest_maximumRecordSize :
+ m_client->m_initResponse_maximumRecordSize);
+ }
+ int r = send_PDU_convert(apdu);
+ if (r)
+ return r;
+ if (kill_session)
+ {
+ delete m_client;
+ m_client = 0;
+ m_parent->pre_init();
+ }
+ return r;
+}
+
+int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
+{
+ int len = 0;
+ const char *apdu_name_tmp = apdu_name(apdu);
+ int r = send_Z_PDU(apdu, &len);
+ if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
+ yaz_log (LOG_LOG, "%sSending %s to %s %d bytes",
+ get_session_str(),
+ apdu_name_tmp, get_hostname(), len);
+ m_bytes_sent += len;
+ return r;
+}
+
+Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ int toget = *pr->numberOfRecordsRequested;
+ int start = *pr->resultSetStartPoint;
+
+ yaz_log(LOG_LOG, "%sPresent %s %d+%d", m_session_str,
+ pr->resultSetId, start, toget);
+
+ if (*m_parent->m_optimize == '0')
+ return apdu;
+
+ if (!m_client->m_last_resultSetId)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 30,
+ pr->resultSetId);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId))
+ {
+ if (start+toget-1 > m_client->m_last_resultCount)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), 13, 0);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ Z_NamePlusRecordList *npr;
+ if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
+ pr->preferredRecordSyntax,
+ pr->recordComposition))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for present request",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+
+ new_apdu->u.presentResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.presentResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.presentResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), start+toget);
+
+ send_to_client(new_apdu);
+ return 0;
+ }
+ }
+ }
+
+ if (apdu->which != Z_APDU_searchRequest)
+ return apdu;
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ Yaz_Z_Query *this_query = new Yaz_Z_Query;
+ Yaz_Z_Databases this_databases;
+
+ this_databases.set(sr->num_databaseNames, (const char **)
+ sr->databaseNames);
+
+ this_query->set_Z_Query(sr->query);
+
+ char query_str[120];
+ this_query->print(query_str, sizeof(query_str)-1);
+ yaz_log(LOG_LOG, "%sSearch %s", m_session_str, query_str);
+
+ if (*m_parent->m_optimize != '0' &&
+ m_client->m_last_ok && m_client->m_last_query &&
+ m_client->m_last_query->match(this_query) &&
+ !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
+ m_client->m_last_databases.match(this_databases))
+ {
+ delete this_query;
+ if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
+ m_client->m_last_resultCount < *sr->largeSetLowerBound)
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = *sr->mediumSetPresentNumber;
+ Z_RecordComposition *comp = 0;
+
+ if (toget > m_client->m_last_resultCount)
+ toget = m_client->m_last_resultCount;
+
+ if (sr->mediumSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->mediumSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for medium set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ // medium Set
+ // send present request (medium size)
+ yaz_log (LOG_LOG, "%sOptimizing search for medium set",
+ m_session_str);
+
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
+ m_client->m_last_resultCount <= 0)
+ {
+ // large set. Return pseudo-search response immediately
+ yaz_log (LOG_LOG, "%sOptimizing search for large set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ Z_NamePlusRecordList *npr;
+ int toget = m_client->m_last_resultCount;
+ Z_RecordComposition *comp = 0;
+ // small set
+ // send a present request (small set)
+
+ if (sr->smallSetElementSetNames)
+ {
+ comp = (Z_RecordComposition *)
+ odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
+ comp->which = Z_RecordComp_simple;
+ comp->u.simple = sr->smallSetElementSetNames;
+ }
+
+ if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
+ sr->preferredRecordSyntax, comp))
+ {
+ yaz_log (LOG_LOG, "%sReturned cached records for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->resultCount =
+ &m_client->m_last_resultCount;
+
+ new_apdu->u.searchResponse->numberOfRecordsReturned
+ = odr_intdup(odr_encode(), toget);
+
+ new_apdu->u.searchResponse->presentStatus =
+ odr_intdup(odr_encode(), Z_PresentStatus_success);
+ new_apdu->u.searchResponse->records = (Z_Records*)
+ odr_malloc(odr_encode(), sizeof(Z_Records));
+ new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
+ new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
+ new_apdu->u.searchResponse->nextResultSetPosition =
+ odr_intdup(odr_encode(), toget+1);
+ send_to_client(new_apdu);
+ return 0;
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sOptimizing search for small set",
+ m_session_str);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
+ Z_PresentRequest *pr = new_apdu->u.presentRequest;
+ pr->referenceId = sr->referenceId;
+ pr->resultSetId = sr->resultSetName;
+ pr->preferredRecordSyntax = sr->preferredRecordSyntax;
+ *pr->numberOfRecordsRequested = toget;
+ pr->recordComposition = comp;
+ m_client->m_sr_transform = 1;
+ return new_apdu;
+ }
+ }
+ }
+ else // query doesn't match
+ {
+ delete m_client->m_last_query;
+ m_client->m_last_query = this_query;
+ m_client->m_last_ok = 0;
+ m_client->m_cache.clear();
+ m_client->m_resultSetStartPoint = 0;
+
+ xfree (m_client->m_last_resultSetId);
+ m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
+
+ m_client->m_last_databases.set(sr->num_databaseNames,
+ (const char **) sr->databaseNames);
+ }
+ return apdu;
+}
+
+
+void Yaz_Proxy::inc_request_no()
+{
+ char *cp = strchr(m_session_str, ' ');
+ m_request_no++;
+ if (cp)
+ sprintf(cp+1, "%d ", m_request_no);
+}
+
+void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
+{
+ inc_request_no();
+
+ m_bytes_recv += len;
+
+ if (m_log_mask & PROXY_LOG_REQ_CLIENT)
+ yaz_log (LOG_LOG, "%sReceiving %s from client %d bytes",
+ m_session_str, gdu_name(apdu), len);
+
+ if (m_bw_hold_PDU) // double incoming PDU. shutdown now.
+ shutdown();
+
+ m_bw_stat.add_bytes(len);
+ m_pdu_stat.add_bytes(1);
+
+ gettimeofday(&m_time_tv, 0);
+
+ int bw_total = m_bw_stat.get_total();
+ int pdu_total = m_pdu_stat.get_total();
+
+ int reduce = 0;
+ if (m_bw_max)
+ {
+ if (bw_total > m_bw_max)
+ {
+ reduce = (bw_total/m_bw_max);
+ }
+ }
+ if (m_pdu_max)
+ {
+ if (pdu_total > m_pdu_max)
+ {
+ int nreduce = (m_pdu_max >= 60) ? 1 : 60/m_pdu_max;
+ reduce = (reduce > nreduce) ? reduce : nreduce;
+ }
+ }
+ if (reduce)
+ {
+ yaz_log(LOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, reduce, bw_total, pdu_total,
+ m_bw_max, m_pdu_max);
+
+ m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
+ timeout(reduce); // call us reduce seconds later
+ }
+ else if (apdu->which == Z_GDU_Z3950)
+ handle_incoming_Z_PDU(apdu->u.z3950);
+ else if (apdu->which == Z_GDU_HTTP_Request)
+ handle_incoming_HTTP(apdu->u.HTTP_Request);
+}
+
+void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
+{
+ if (m_max_record_retrieve)
+ {
+ if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ if (pr->numberOfRecordsRequested &&
+ *pr->numberOfRecordsRequested > m_max_record_retrieve)
+ *pr->numberOfRecordsRequested = m_max_record_retrieve;
+ }
+ }
+}
+
+Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
+ int error,
+ const char *addinfo)
+{
+ Z_Records *rec = (Z_Records *)
+ odr_malloc (odr, sizeof(*rec));
+ int *err = (int *)
+ odr_malloc (odr, sizeof(*err));
+ Z_DiagRec *drec = (Z_DiagRec *)
+ odr_malloc (odr, sizeof(*drec));
+ Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
+ odr_malloc (odr, sizeof(*dr));
+ *err = error;
+ rec->which = Z_Records_NSD;
+ rec->u.nonSurrogateDiagnostic = dr;
+ dr->diagnosticSetId =
+ yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
+ dr->condition = err;
+ dr->which = Z_DefaultDiagFormat_v2Addinfo;
+ dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
+ return rec;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest &&
+ apdu->u.searchRequest->query &&
+ apdu->u.searchRequest->query->which == Z_Query_type_104 &&
+ apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL)
+ {
+ Z_RPNQuery *rpnquery = 0;
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ char *addinfo = 0;
+
+ yaz_log(LOG_LOG, "%sCQL: %s", m_session_str,
+ sr->query->u.type_104->u.cql);
+
+ int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
+ &rpnquery, odr_encode(),
+ &addinfo);
+ if (r == -3)
+ yaz_log(LOG_LOG, "%sNo CQL to RPN table", m_session_str);
+ else if (r)
+ {
+ yaz_log(LOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(),
+ yaz_diag_srw_to_bib1(r),
+ addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ else
+ {
+ sr->query->which = Z_Query_type_1;
+ sr->query->u.type_1 = rpnquery;
+ }
+ return apdu;
+ }
+ return apdu;
+}
+
+Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
+{
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ int err = 0;
+ char *addinfo = 0;
+
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+ if (cfg)
+ err = cfg->check_query(odr_encode(), m_default_target,
+ sr->query, &addinfo);
+ if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
+Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
+{
+ m_marcxml_flag = 0;
+ if (apdu->which == Z_APDU_searchRequest)
+ {
+ Z_SearchRequest *sr = apdu->u.searchRequest;
+ int err = 0;
+ char *addinfo = 0;
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ Z_RecordComposition rc_temp, *rc = 0;
+ if (sr->smallSetElementSetNames)
+ {
+ rc_temp.which = Z_RecordComp_simple;
+ rc_temp.u.simple = sr->smallSetElementSetNames;
+ rc = &rc_temp;
+ }
+
+ char *stylesheet_name = 0;
+ if (cfg)
+ err = cfg->check_syntax(odr_encode(),
+ m_default_target,
+ sr->preferredRecordSyntax, rc,
+ &addinfo, &stylesheet_name, &m_schema);
+ if (stylesheet_name)
+ {
+ m_parent->low_socket_close();
+
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+
+ m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
+ stylesheet_name);
+ m_stylesheet_offset = 0;
+ xfree(stylesheet_name);
+
+ m_parent->low_socket_open();
+ }
+ if (err == -1)
+ {
+ sr->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN, VAL_USMARC);
+ m_marcxml_flag = 1;
+ }
+ else if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+
+ new_apdu->u.searchResponse->referenceId = sr->referenceId;
+ new_apdu->u.searchResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.searchResponse->searchStatus = 0;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ else if (apdu->which == Z_APDU_presentRequest)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ int err = 0;
+ char *addinfo = 0;
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ char *stylesheet_name = 0;
+ if (cfg)
+ err = cfg->check_syntax(odr_encode(), m_default_target,
+ pr->preferredRecordSyntax,
+ pr->recordComposition,
+ &addinfo, &stylesheet_name, &m_schema);
+ if (stylesheet_name)
+ {
+ m_parent->low_socket_close();
+
+ if (m_stylesheet_xsp)
+ xsltFreeStylesheet(m_stylesheet_xsp);
+
+ m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
+ stylesheet_name);
+ m_stylesheet_offset = 0;
+ xfree(stylesheet_name);
+
+ m_parent->low_socket_open();
+ }
+ if (err == -1)
+ {
+ pr->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(odr_decode(), CLASS_RECSYN, VAL_USMARC);
+ m_marcxml_flag = 1;
+ }
+ else if (err)
+ {
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
+
+ new_apdu->u.presentResponse->referenceId = pr->referenceId;
+ new_apdu->u.presentResponse->records =
+ create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
+ *new_apdu->u.presentResponse->presentStatus =
+ Z_PresentStatus_failure;
+
+ send_to_client(new_apdu);
+
+ return 0;
+ }
+ }
+ return apdu;
+}
+
+Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
+{
+ if (!schema)
+ return 0;
+ Z_ElementSetNames *esn = (Z_ElementSetNames *)
+ odr_malloc(o, sizeof(Z_ElementSetNames));
+ esn->which = Z_ElementSetNames_generic;
+ esn->u.generic = odr_strdup(o, schema);
+ return esn;
+}
+
+void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
+{
+ if (m_s2z_odr_init)
+ {
+ odr_destroy(m_s2z_odr_init);
+ m_s2z_odr_init = 0;
+ }
+ if (m_s2z_odr_search)
+ {
+ odr_destroy(m_s2z_odr_search);
+ m_s2z_odr_search = 0;
+ }
+
+ m_http_keepalive = 0;
+ m_http_version = 0;
+ if (!strcmp(hreq->version, "1.0"))
+ {
+ const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
+ if (v && !strcmp(v, "Keep-Alive"))
+ m_http_keepalive = 1;
+ else
+ m_http_keepalive = 0;
+ m_http_version = "1.0";
+ }
+ else
+ {
+ const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
+ if (v && !strcmp(v, "close"))
+ m_http_keepalive = 0;
+ else
+ m_http_keepalive = 1;
+ m_http_version = "1.1";
+ }
+
+ Z_SRW_PDU *srw_pdu = 0;
+ Z_SOAP *soap_package = 0;
+ char *charset = 0;
+ Z_SRW_diagnostic *diagnostic = 0;
+ int num_diagnostic = 0;
+ if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+ &charset) == 0
+ || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
+ &charset, &diagnostic, &num_diagnostic) == 0)
+ {
+ m_s2z_odr_init = odr_createmem(ODR_ENCODE);
+ m_s2z_odr_search = odr_createmem(ODR_ENCODE);
+ m_soap_ns = odr_strdup(m_s2z_odr_search, soap_package->ns);
+ m_s2z_init_apdu = 0;
+ m_s2z_search_apdu = 0;
+ m_s2z_present_apdu = 0;
+
+ m_s2z_stylesheet = 0;
+
+ if (srw_pdu->which == Z_SRW_searchRetrieve_request)
+ {
+ Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
+
+ m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
+ // recordXPath unsupported.
+ if (srw_req->recordXPath)
+ {
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 72, 0);
+ }
+ // must have a query
+ if (!srw_req->query.cql)
+ {
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 7, "query");
+ }
+ // sort unsupported
+ if (srw_req->sort_type != Z_SRW_sort_type_none)
+ {
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 80, 0);
+ }
+ // save stylesheet
+ if (srw_req->stylesheet)
+ m_s2z_stylesheet =
+ odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+
+ // set packing for response records ..
+ if (srw_req->recordPacking &&
+ !strcmp(srw_req->recordPacking, "xml"))
+ m_s2z_packing = Z_SRW_recordPacking_XML;
+ else
+ m_s2z_packing = Z_SRW_recordPacking_string;
+
+ if (num_diagnostic)
+ {
+ Z_SRW_PDU *srw_pdu =
+ yaz_srw_get(odr_encode(),
+ Z_SRW_searchRetrieve_response);
+ Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
+
+ srw_res->diagnostics = diagnostic;
+ srw_res->num_diagnostics = num_diagnostic;
+ send_srw_response(srw_pdu);
+ return;
+ }
+
+ // prepare search PDU
+ m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
+ Z_APDU_searchRequest);
+ Z_SearchRequest *z_searchRequest =
+ m_s2z_search_apdu->u.searchRequest;
+
+ z_searchRequest->num_databaseNames = 1;
+ z_searchRequest->databaseNames = (char**)
+ odr_malloc(m_s2z_odr_search, sizeof(char *));
+ z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
+ srw_req->database);
+
+ // query transformation
+ Z_Query *query = (Z_Query *)
+ odr_malloc(m_s2z_odr_search, sizeof(Z_Query));
+ z_searchRequest->query = query;
+
+ if (srw_req->query_type == Z_SRW_query_type_cql)
+ {
+ Z_External *ext = (Z_External *)
+ odr_malloc(m_s2z_odr_search, sizeof(*ext));
+ ext->direct_reference =
+ odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
+ ext->indirect_reference = 0;
+ ext->descriptor = 0;
+ ext->which = Z_External_CQL;
+ ext->u.cql = srw_req->query.cql;
+
+ query->which = Z_Query_type_104;
+ query->u.type_104 = ext;
+ }
+ else if (srw_req->query_type == Z_SRW_query_type_pqf)
+ {
+ Z_RPNQuery *RPNquery;
+ YAZ_PQF_Parser pqf_parser;
+
+ pqf_parser = yaz_pqf_create ();
+
+ RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
+ srw_req->query.pqf);
+ if (!RPNquery)
+ {
+ const char *pqf_msg;
+ size_t off;
+ int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
+ yaz_log(LOG_LOG, "%*s^\n", off+4, "");
+ yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
+
+ send_to_srw_client_error(10, 0);
+ return;
+ }
+ query->which = Z_Query_type_1;
+ query->u.type_1 = RPNquery;
+
+ yaz_pqf_destroy (pqf_parser);
+ }
+ else
+ {
+ send_to_srw_client_error(7, "query");
+ return;
+ }
+
+ // present
+ m_s2z_present_apdu = 0;
+ int max = 0;
+ if (srw_req->maximumRecords)
+ max = *srw_req->maximumRecords;
+ int start = 1;
+ if (srw_req->startRecord)
+ start = *srw_req->startRecord;
+ if (max > 0)
+ {
+ // Some backend, such as Voyager doesn't honor piggyback
+ // So we use present always (0 &&).
+ if (0 && start <= 1) // Z39.50 piggyback
+ {
+ *z_searchRequest->smallSetUpperBound = max;
+ *z_searchRequest->mediumSetPresentNumber = max;
+ *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
+
+ z_searchRequest->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
+ VAL_TEXT_XML);
+ if (srw_req->recordSchema)
+ {
+ z_searchRequest->smallSetElementSetNames =
+ z_searchRequest->mediumSetElementSetNames =
+ mk_esn_from_schema(m_s2z_odr_search,
+ srw_req->recordSchema);
+ }
+ }
+ else // Z39.50 present
+ {
+ m_s2z_present_apdu = zget_APDU(m_s2z_odr_search,
+ Z_APDU_presentRequest);
+ Z_PresentRequest *z_presentRequest =
+ m_s2z_present_apdu->u.presentRequest;
+ *z_presentRequest->resultSetStartPoint = start;
+ *z_presentRequest->numberOfRecordsRequested = max;
+ z_presentRequest->preferredRecordSyntax =
+ yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
+ VAL_TEXT_XML);
+ if (srw_req->recordSchema)
+ {
+ z_presentRequest->recordComposition =
+ (Z_RecordComposition *)
+ odr_malloc(m_s2z_odr_search,
+ sizeof(Z_RecordComposition));
+ z_presentRequest->recordComposition->which =
+ Z_RecordComp_simple;
+ z_presentRequest->recordComposition->u.simple =
+ mk_esn_from_schema(m_s2z_odr_search,
+ srw_req->recordSchema);
+ }
+ }
+ }
+ if (!m_client)
+ {
+ m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
+ Z_APDU_initRequest);
+
+ // prevent m_initRequest_apdu memory from being grabbed
+ // in Yaz_Proxy::handle_incoming_Z_PDU
+ m_initRequest_apdu = m_s2z_init_apdu;
+ handle_incoming_Z_PDU(m_s2z_init_apdu);
+ return;
+ }
+ else
+ {
+ handle_incoming_Z_PDU(m_s2z_search_apdu);
+ return;
+ }
+ }
+ else if (srw_pdu->which == Z_SRW_explain_request)
+ {
+ Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
+
+ m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
+
+ // save stylesheet
+ if (srw_req->stylesheet)
+ m_s2z_stylesheet =
+ odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
+
+ if (srw_req->recordPacking &&
+ !strcmp(srw_req->recordPacking, "xml"))
+ m_s2z_packing = Z_SRW_recordPacking_XML;
+ else
+ m_s2z_packing = Z_SRW_recordPacking_string;
+
+ if (num_diagnostic)
+ {
+ send_srw_explain_response(diagnostic, num_diagnostic);
+ return;
+ }
+
+ if (!m_client)
+ {
+ m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
+ Z_APDU_initRequest);
+
+ // prevent m_initRequest_apdu memory from being grabbed
+ // in Yaz_Proxy::handle_incoming_Z_PDU
+ m_initRequest_apdu = m_s2z_init_apdu;
+ handle_incoming_Z_PDU(m_s2z_init_apdu);
+ }
+ else
+ send_srw_explain_response(0, 0);
+ return;
+ }
+ else if (srw_pdu->which == Z_SRW_scan_request)
+ {
+ m_s2z_database = odr_strdup(m_s2z_odr_init,
+ srw_pdu->u.scan_request->database);
+
+ yaz_add_srw_diagnostic(odr_decode(),
+ &diagnostic, &num_diagnostic,
+ 4, "scan");
+ Z_SRW_PDU *srw_pdu =
+ yaz_srw_get(odr_encode(),
+ Z_SRW_scan_response);
+ Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
+
+ srw_res->diagnostics = diagnostic;
+ srw_res->num_diagnostics = num_diagnostic;
+ send_srw_response(srw_pdu);
+ return;
+ }
+ else
+ {
+ m_s2z_database = 0;
+
+ send_to_srw_client_error(4, 0);
+ }
+ }
+ int len = 0;
+ Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);
+ timeout(0);
+ send_GDU(p, &len);
+}
+
+void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
+{
+ Z_ReferenceId **refid = get_referenceIdP(apdu);
+ nmem_reset(m_referenceId_mem);
+ if (refid && *refid)
+ {
+ m_referenceId = (Z_ReferenceId *)
+ nmem_malloc(m_referenceId_mem, sizeof(*m_referenceId));
+ m_referenceId->len = m_referenceId->size = (*refid)->len;
+ m_referenceId->buf = (unsigned char *)
+ nmem_malloc(m_referenceId_mem, (*refid)->len);
+ memcpy(m_referenceId->buf, (*refid)->buf, (*refid)->len);
+ }
+ else
+ m_referenceId = 0;
+
+ if (!m_client && m_invalid_session)
+ {
+ m_apdu_invalid_session = apdu;
+ m_mem_invalid_session = odr_extract_mem(odr_decode());
+ apdu = m_initRequest_apdu;
+ }
+
+ // Determine our client.
+ Z_OtherInformation **oi;
+ get_otherInfoAPDU(apdu, &oi);
+ m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
+ if (!m_client)
+ {
+ delete this;
+ return;
+ }
+ m_client->m_server = this;
+
+ if (apdu->which == Z_APDU_initRequest)
+ {
+ if (apdu->u.initRequest->implementationId)
+ yaz_log(LOG_LOG, "%simplementationId: %s",
+ m_session_str, apdu->u.initRequest->implementationId);
+ if (apdu->u.initRequest->implementationName)
+ yaz_log(LOG_LOG, "%simplementationName: %s",
+ m_session_str, apdu->u.initRequest->implementationName);
+ if (apdu->u.initRequest->implementationVersion)
+ yaz_log(LOG_LOG, "%simplementationVersion: %s",
+ m_session_str, apdu->u.initRequest->implementationVersion);
+ if (m_initRequest_apdu == 0)
+ {
+ if (m_initRequest_mem)
+ nmem_destroy(m_initRequest_mem);
+ m_initRequest_apdu = apdu;
+ m_initRequest_mem = odr_extract_mem(odr_decode());
+
+ m_initRequest_preferredMessageSize = *apdu->u.initRequest->
+ preferredMessageSize;
+ *apdu->u.initRequest->preferredMessageSize = 1024*1024;
+ m_initRequest_maximumRecordSize = *apdu->u.initRequest->
+ maximumRecordSize;
+ *apdu->u.initRequest->maximumRecordSize = 1024*1024;
+
+ // save init options for the response..
+ m_initRequest_options = apdu->u.initRequest->options;
+
+ apdu->u.initRequest->options =
+ (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(apdu->u.initRequest->options);
+ int i;
+ for (i = 0; i<= 24; i++)
+ ODR_MASK_SET(apdu->u.initRequest->options, i);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_negotiationModel);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_concurrentOperations);
+
+ // make new version
+ m_initRequest_version = apdu->u.initRequest->protocolVersion;
+ apdu->u.initRequest->protocolVersion =
+ (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
+ sizeof(Odr_bitmask));
+ ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
+
+ for (i = 0; i<= 8; i++)
+ ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
+ }
+ if (m_client->m_init_flag)
+ {
+ if (handle_init_response_for_invalid_session(apdu))
+ return;
+ if (m_client->m_initResponse)
+ {
+ Z_APDU *apdu2 = m_client->m_initResponse;
+ apdu2->u.initResponse->otherInfo = 0;
+ if (m_client->m_cookie && *m_client->m_cookie)
+ set_otherInformationString(apdu2, VAL_COOKIE, 1,
+ m_client->m_cookie);
+ apdu2->u.initResponse->referenceId =
+ apdu->u.initRequest->referenceId;
+ apdu2->u.initResponse->options = m_client->m_initResponse_options;
+ apdu2->u.initResponse->protocolVersion =
+ m_client->m_initResponse_version;
+
+ send_to_client(apdu2);
+ return;
+ }
+ }
+ m_client->m_init_flag = 1;
+ }
+ handle_max_record_retrieve(apdu);
+
+ if (apdu)
+ apdu = handle_syntax_validation(apdu);
+
+ if (apdu)
+ apdu = handle_query_transformation(apdu);
+
+ if (apdu)
+ apdu = handle_query_validation(apdu);
+
+ if (apdu)
+ apdu = result_set_optimize(apdu);
+ if (!apdu)
+ {
+ m_client->timeout(m_target_idletime); // mark it active even
+ // though we didn't use it
+ return;
+ }
+
+ // delete other info part from PDU before sending to target
+ get_otherInfoAPDU(apdu, &oi);
+ if (oi)
+ *oi = 0;
+
+ if (apdu->which == Z_APDU_presentRequest &&
+ m_client->m_resultSetStartPoint == 0)
+ {
+ Z_PresentRequest *pr = apdu->u.presentRequest;
+ m_client->m_resultSetStartPoint = *pr->resultSetStartPoint;
+ m_client->m_cache.copy_presentRequest(apdu->u.presentRequest);
+ } else {
+ m_client->m_resultSetStartPoint = 0;
+ }
+ if (m_client->send_to_target(apdu) < 0)
+ {
+ delete m_client;
+ m_client = 0;
+ delete this;
+ }
+ else
+ m_client->m_waiting = 1;
+}
+
+void Yaz_Proxy::connectNotify()
+{
+}
+
+void Yaz_Proxy::shutdown()
+{
+ m_invalid_session = 0;
+ // only keep if keep_alive flag is set...
+ if (m_client &&
+ m_client->m_pdu_recv < m_keepalive_limit_pdu &&
+ m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
+ m_client->m_waiting == 0)
+ {
+ yaz_log(LOG_LOG, "%sShutdown (client to proxy) keepalive %s",
+ m_session_str,
+ m_client->get_hostname());
+ yaz_log(LOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
+ m_session_str, m_client->m_pdu_recv,
+ m_client->m_bytes_sent + m_client->m_bytes_recv,
+ m_keepalive_limit_bw, m_keepalive_limit_pdu);
+ assert (m_client->m_waiting != 2);
+ // Tell client (if any) that no server connection is there..
+ m_client->m_server = 0;
+ m_invalid_session = 0;
+ }
+ else if (m_client)
+ {
+ yaz_log (LOG_LOG, "%sShutdown (client to proxy) close %s",
+ m_session_str,
+ m_client->get_hostname());
+ assert (m_client->m_waiting != 2);
+ delete m_client;
+ }
+ else if (!m_parent)
+ {
+ yaz_log (LOG_LOG, "%sshutdown (client to proxy) bad state",
+ m_session_str);
+ assert (m_parent);
+ }
+ else
+ {
+ yaz_log (LOG_LOG, "%sShutdown (client to proxy)",
+ m_session_str);
+ }
+ if (m_parent)
+ m_parent->pre_init();
+ delete this;
+}
+
+const char *Yaz_ProxyClient::get_session_str()
+{
+ if (!m_server)
+ return "0 ";
+ return m_server->get_session_str();
+}
+
+void Yaz_ProxyClient::shutdown()
+{
+ yaz_log (LOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
+ get_hostname());
+ delete m_server;
+ delete this;
+}
+
+void Yaz_Proxy::failNotify()
+{
+ inc_request_no();
+ yaz_log (LOG_LOG, "%sConnection closed by client",
+ get_session_str());
+ shutdown();
+}
+
+void Yaz_ProxyClient::failNotify()
+{
+ if (m_server)
+ m_server->inc_request_no();
+ yaz_log (LOG_LOG, "%sConnection closed by target %s",
+ get_session_str(), get_hostname());
+ shutdown();
+}
+
+void Yaz_ProxyClient::connectNotify()
+{
+ const char *s = get_session_str();
+ const char *h = get_hostname();
+ yaz_log (LOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
+ m_target_idletime);
+ timeout(m_target_idletime);
+ if (!m_server)
+ pre_init_client();
+}
+
+IYaz_PDU_Observer *Yaz_ProxyClient::sessionNotify(IYaz_PDU_Observable
+ *the_PDU_Observable, int fd)
+{
+ return new Yaz_ProxyClient(the_PDU_Observable, 0);
+}
+
+Yaz_ProxyClient::~Yaz_ProxyClient()
+{
+ if (m_prev)
+ *m_prev = m_next;
+ if (m_next)
+ m_next->m_prev = m_prev;
+ m_waiting = 2; // for debugging purposes only.
+ odr_destroy(m_init_odr);
+ delete m_last_query;
+ xfree (m_last_resultSetId);
+ xfree (m_cookie);
+}
+
+void Yaz_ProxyClient::pre_init_client()
+{
+ Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
+ Z_InitRequest *req = apdu->u.initRequest;
+
+ int i;
+ for (i = 0; i<= 24; i++)
+ ODR_MASK_SET(req->options, i);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_negotiationModel);
+ ODR_MASK_CLEAR(apdu->u.initRequest->options,
+ Z_Options_concurrentOperations);
+ for (i = 0; i<= 10; i++)
+ ODR_MASK_SET(req->protocolVersion, i);
+
+ if (send_to_target(apdu) < 0)
+ {
+ delete this;
+ }
+ else
+ {
+ m_waiting = 1;
+ m_init_flag = 1;
+ }
+}
+
+void Yaz_Proxy::pre_init()
+{
+ int i;
+ const char *name = 0;
+ const char *zurl_in_use[MAX_ZURL_PLEX];
+ int limit_bw, limit_pdu, limit_req;
+ int target_idletime, client_idletime;
+ int max_clients;
+ int keepalive_limit_bw, keepalive_limit_pdu;
+ int pre_init;
+ const char *cql2rpn = 0;
+
+ Yaz_ProxyConfig *cfg = check_reconfigure();
+
+ zurl_in_use[0] = 0;
+
+ if (m_log_mask & PROXY_LOG_APDU_CLIENT)
+ set_APDU_yazlog(1);
+ else
+ set_APDU_yazlog(0);
+
+ for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use,
+ &limit_bw, &limit_pdu, &limit_req,
+ &target_idletime, &client_idletime,
+ &max_clients,
+ &keepalive_limit_bw,
+ &keepalive_limit_pdu,
+ &pre_init,
+ &cql2rpn) ; i++)
+ {
+ if (pre_init)
+ {
+ int j;
+ for (j = 0; zurl_in_use[j]; j++)
+ {
+ Yaz_ProxyClient *c;
+ int spare = 0;
+ int spare_waiting = 0;
+ int in_use = 0;
+ int other = 0;
+ for (c = m_clientPool; c; c = c->m_next)
+ {
+ if (!strcmp(zurl_in_use[j], c->get_hostname()))
+ {
+ if (c->m_cookie == 0)
+ {
+ if (c->m_server == 0)
+ if (c->m_waiting)
+ spare_waiting++;
+ else
+ spare++;
+ else
+ in_use++;
+ }
+ else
+ other++;
+ }
+ }
+ yaz_log(LOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
+ "sparew=%d preinit=%d",m_session_str,
+ name, zurl_in_use[j], in_use, other,
+ spare, spare_waiting, pre_init);
+ if (spare + spare_waiting < pre_init)
+ {
+ c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
+ c->m_next = m_clientPool;
+ if (c->m_next)
+ c->m_next->m_prev = &c->m_next;
+ m_clientPool = c;
+ c->m_prev = &m_clientPool;
+
+ if (m_log_mask & PROXY_LOG_APDU_SERVER)
+ c->set_APDU_yazlog(1);
+ else
+ c->set_APDU_yazlog(0);
+
+ if (c->client(zurl_in_use[j]))
+ {
+ timeout(60);
+ delete c;
+ return;
+ }
+ c->timeout(30);
+ c->m_waiting = 1;
+ c->m_target_idletime = target_idletime;
+ c->m_seqno = m_seqno++;
+ }
+ }
+ }
+ }
+}
+
+void Yaz_Proxy::timeoutNotify()
+{
+ if (m_parent)
+ {
+ if (m_bw_hold_PDU)
+ {
+ timeout(m_client_idletime);
+ Z_GDU *apdu = m_bw_hold_PDU;
+ m_bw_hold_PDU = 0;
+
+ if (apdu->which == Z_GDU_Z3950)
+ handle_incoming_Z_PDU(apdu->u.z3950);
+ else if (apdu->which == Z_GDU_HTTP_Request)
+ handle_incoming_HTTP(apdu->u.HTTP_Request);
+ }
+ else if (m_stylesheet_nprl)
+ convert_xsl_delay();
+ else
+ {
+ inc_request_no();
+
+ yaz_log (LOG_LOG, "%sTimeout (client to proxy)", m_session_str);
+ shutdown();
+ }
+ }
+ else
+ {
+ timeout(600);
+ pre_init();
+ }
+}
+
+void Yaz_Proxy::markInvalid()
+{
+ m_client = 0;
+ m_invalid_session = 1;
+}
+
+void Yaz_ProxyClient::timeoutNotify()
+{
+ if (m_server)
+ m_server->inc_request_no();
+
+ yaz_log (LOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
+ get_hostname());
+ m_waiting = 1;
+ m_root->pre_init();
+ if (m_server && m_init_flag)
+ {
+ // target timed out in a session that was properly initialized
+ // server object stay alive but we mark it as invalid so it
+ // gets initialized again
+ m_server->markInvalid();
+ m_server = 0;
+ }
+ shutdown();
+}
+
+Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
+ Yaz_Proxy *parent) :
+ Yaz_Z_Assoc (the_PDU_Observable)
+{
+ m_cookie = 0;
+ m_next = 0;
+ m_prev = 0;
+ m_init_flag = 0;
+ m_last_query = 0;
+ m_last_resultSetId = 0;
+ m_last_resultCount = 0;
+ m_last_ok = 0;
+ m_sr_transform = 0;
+ m_waiting = 0;
+ m_init_odr = odr_createmem (ODR_DECODE);
+ m_initResponse = 0;
+ m_initResponse_options = 0;
+ m_initResponse_version = 0;
+ m_initResponse_preferredMessageSize = 0;
+ m_initResponse_maximumRecordSize = 0;
+ m_resultSetStartPoint = 0;
+ m_bytes_sent = m_bytes_recv = 0;
+ m_pdu_recv = 0;
+ m_server = 0;
+ m_seqno = 0;
+ m_target_idletime = 600;
+ m_root = parent;
+}
+
+const char *Yaz_Proxy::option(const char *name, const char *value)
+{
+ if (!strcmp (name, "optimize")) {
+ if (value) {
+ xfree (m_optimize);
+ m_optimize = xstrdup (value);
+ }
+ return m_optimize;
+ }
+ return 0;
+}
+
+void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len)
+{
+
+}
+
+void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len)
+{
+ if (apdu->which == Z_GDU_Z3950)
+ recv_Z_PDU(apdu->u.z3950, len);
+ else if (apdu->which == Z_GDU_HTTP_Response)
+ recv_HTTP_response(apdu->u.HTTP_Response, len);
+ else
+ shutdown();
+}
+
+int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu)
+{
+ if (!m_invalid_session)
+ return 0;
+ m_invalid_session = 0;
+ handle_incoming_Z_PDU(m_apdu_invalid_session);
+ assert (m_mem_invalid_session);
+ nmem_destroy(m_mem_invalid_session);
+ m_mem_invalid_session = 0;
+ return 1;
+}
+
+void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
+{
+ m_bytes_recv += len;
+
+ m_pdu_recv++;
+ m_waiting = 0;
+ if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
+ yaz_log (LOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
+ apdu_name(apdu), get_hostname(), len);
+ if (apdu->which == Z_APDU_initResponse)
+ {
+ if (!m_server) // if this is a pre init session , check for more
+ m_root->pre_init();
+ NMEM nmem = odr_extract_mem (odr_decode());
+ odr_reset (m_init_odr);
+ nmem_transfer (m_init_odr->mem, nmem);
+ m_initResponse = apdu;
+ m_initResponse_options = apdu->u.initResponse->options;
+ m_initResponse_version = apdu->u.initResponse->protocolVersion;
+ m_initResponse_preferredMessageSize =
+ *apdu->u.initResponse->preferredMessageSize;
+ m_initResponse_maximumRecordSize =
+ *apdu->u.initResponse->maximumRecordSize;
+
+ Z_InitResponse *ir = apdu->u.initResponse;
+ char *im0 = ir->implementationName;
+
+ char *im1 = (char*)
+ odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
+ *im1 = '\0';
+ if (im0)
+ {
+ strcat(im1, im0);
+ strcat(im1, " ");
+ }
+ strcat(im1, "(YAZ Proxy)");
+ ir->implementationName = im1;
+
+ nmem_destroy (nmem);
+
+ if (m_server && m_server->handle_init_response_for_invalid_session(apdu))
+ return;
+ }
+ if (apdu->which == Z_APDU_searchResponse)
+ {
+ Z_SearchResponse *sr = apdu->u.searchResponse;
+ m_last_resultCount = *sr->resultCount;
+ int status = *sr->searchStatus;
+ if (status && (!sr->records || sr->records->which == Z_Records_DBOSD))
+ {
+ m_last_ok = 1;
+
+ if (sr->records && sr->records->which == Z_Records_DBOSD)
+ {
+ m_cache.add(odr_decode(),
+ sr->records->u.databaseOrSurDiagnostics, 1,
+ *sr->resultCount);
+ }
+ }
+ }
+ if (apdu->which == Z_APDU_presentResponse)
+ {
+ Z_PresentResponse *pr = apdu->u.presentResponse;
+ if (m_sr_transform)
+ {
+ m_sr_transform = 0;
+ Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
+ Z_SearchResponse *sr = new_apdu->u.searchResponse;
+ sr->referenceId = pr->referenceId;
+ *sr->resultCount = m_last_resultCount;
+ sr->records = pr->records;
+ sr->nextResultSetPosition = pr->nextResultSetPosition;
+ sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
+ apdu = new_apdu;
+ }
+ if (pr->records &&
+ pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
+ {
+ m_cache.add(odr_decode(),
+ pr->records->u.databaseOrSurDiagnostics,
+ m_resultSetStartPoint, -1);
+ m_resultSetStartPoint = 0;
+ }
+ }
+ if (m_cookie)
+ set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
+ if (m_server)
+ {
+ m_server->send_to_client(apdu);
+ }
+ if (apdu->which == Z_APDU_close)
+ {
+ shutdown();
+ }
+}
+
+void Yaz_Proxy::low_socket_close()
+{
+ int i;
+ for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
+ if (m_lo_fd[i] >= 0)
+ ::close(m_lo_fd[i]);
+}
+
+void Yaz_Proxy::low_socket_open()
+{
+ int i;
+ for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
+ m_lo_fd[i] = open("/dev/null", O_RDONLY);
+}
+
+int Yaz_Proxy::server(const char *addr)
+{
+ int r = Yaz_Z_Assoc::server(addr);
+ if (!r)
+ {
+ yaz_log(LOG_LOG, "%sStarted proxy " VERSION " on %s", m_session_str, addr);
+ timeout(1);
+ }
+ return r;
+}
+
-## $Id: Makefile.am,v 1.22 2004-02-11 10:01:54 adam Exp $
+## $Id: Makefile.am,v 1.23 2004-03-29 22:46:51 adam Exp $
-AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include $(XSLT_CFLAGS)
+AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include
lib_LTLIBRARIES = libyazcpp.la
libyazcpp_la_LDFLAGS=-version-info 1:0:0
libyazcpp_la_SOURCES=yaz-socket-manager.cpp yaz-pdu-assoc.cpp \
- yaz-z-assoc.cpp yaz-proxy.cpp yaz-z-query.cpp yaz-ir-assoc.cpp \
+ yaz-z-assoc.cpp yaz-z-query.cpp yaz-ir-assoc.cpp \
yaz-z-server.cpp yaz-pdu-assoc-thread.cpp yaz-z-server-sr.cpp \
yaz-z-server-ill.cpp yaz-z-server-update.cpp yaz-z-databases.cpp \
- yaz-z-cache.cpp yaz-proxy-config.cpp yaz-bw.cpp yaz-cql2rpn.cpp
+ yaz-z-cache.cpp yaz-cql2rpn.cpp
-bin_PROGRAMS = yaz-proxy
noinst_PROGRAMS = yaz-my-server yaz-my-client
bin_SCRIPTS = yaz++-config
yaz_my_server_SOURCES=yaz-my-server.cpp yaz-marc-sample.cpp
-yaz_proxy_SOURCES=yaz-proxy-main.cpp
-
-LDADD=libyazcpp.la $(YAZLALIB) $(XSLT_LIBS)
+LDADD=libyazcpp.la $(YAZLALIB)
/*
- * Copyright (c) 1998-2003, Index Data.
+ * Copyright (c) 1998-2004, Index Data.
* See the file LICENSE for details.
*
- * $Id: yaz-cql2rpn.cpp,v 1.3 2004-01-06 21:17:42 adam Exp $
+ * $Id: yaz-cql2rpn.cpp,v 1.4 2004-03-29 22:46:51 adam Exp $
*/
#include <yaz/log.h>
#include <yaz/pquery.h>
-#include <yaz++/proxy.h>
+#include <yaz++/cql2rpn.h>
Yaz_cql2rpn::Yaz_cql2rpn()
{
+++ /dev/null
-/*
- * Copyright (c) 1998-2004, Index Data.
- * See the file LICENSE for details.
- *
- * $Id: yaz-proxy-config.cpp,v 1.27 2004-01-30 00:38:28 adam Exp $
- */
-
-#include <ctype.h>
-#include <yaz/log.h>
-#include <yaz++/proxy.h>
-
-Yaz_ProxyConfig::Yaz_ProxyConfig()
-{
- m_copy = 0;
-#if HAVE_XSLT
- m_docPtr = 0;
- m_proxyPtr = 0;
-#endif
-}
-
-Yaz_ProxyConfig::~Yaz_ProxyConfig()
-{
-#if HAVE_XSLT
- if (!m_copy && m_docPtr)
- xmlFreeDoc(m_docPtr);
-#endif
-}
-
-int Yaz_ProxyConfig::read_xml(const char *fname)
-{
-#if HAVE_XSLT
- xmlDocPtr ndoc = xmlParseFile(fname);
-
- if (!ndoc)
- {
- yaz_log(LOG_WARN, "Config file %s not found or parse error", fname);
- return -1; // no good
- }
- xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
- if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
- strcmp((const char *) proxyPtr->name, "proxy"))
- {
- yaz_log(LOG_WARN, "No proxy element in %s", fname);
- xmlFreeDoc(ndoc);
- return -1;
- }
- m_proxyPtr = proxyPtr;
-
- // OK: release previous and make it the current one.
- if (m_docPtr)
- xmlFreeDoc(m_docPtr);
- m_docPtr = ndoc;
- return 0;
-#else
- return -2;
-#endif
-}
-
-#if HAVE_XSLT
-const char *Yaz_ProxyConfig::get_text(xmlNodePtr ptr)
-{
- for(ptr = ptr->children; ptr; ptr = ptr->next)
- if (ptr->type == XML_TEXT_NODE)
- {
- xmlChar *t = ptr->content;
- if (t)
- {
- while (*t == ' ')
- t++;
- return (const char *) t;
- }
- }
- return 0;
-}
-#endif
-
-#if HAVE_XSLT
-void Yaz_ProxyConfig::return_limit(xmlNodePtr ptr,
- int *limit_bw,
- int *limit_pdu,
- int *limit_req)
-{
- for (ptr = ptr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "bandwidth"))
- {
- const char *t = get_text(ptr);
- if (t)
- *limit_bw = atoi(t);
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "retrieve"))
- {
- const char *t = get_text(ptr);
- if (t)
- *limit_req = atoi(t);
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "pdu"))
- {
- const char *t = get_text(ptr);
- if (t)
- *limit_pdu = atoi(t);
- }
- }
-}
-#endif
-
-#if HAVE_XSLT
-void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr,
- const char **url,
- int *limit_bw,
- int *limit_pdu,
- int *limit_req,
- int *target_idletime,
- int *client_idletime,
- int *keepalive_limit_bw,
- int *keepalive_limit_pdu,
- int *pre_init,
- const char **cql2rpn)
-{
- *pre_init = 0;
- int no_url = 0;
- ptr = ptr->children;
- for (; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "preinit"))
- {
- const char *v = get_text(ptr);
- *pre_init = v ? atoi(v) : 1;
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "url"))
- {
- const char *t = get_text(ptr);
- if (t && no_url < MAX_ZURL_PLEX)
- {
- url[no_url++] = t;
- url[no_url] = 0;
- }
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "keepalive"))
- {
- int dummy;
- *keepalive_limit_bw = 500000;
- *keepalive_limit_pdu = 1000;
- return_limit(ptr, keepalive_limit_bw, keepalive_limit_pdu,
- &dummy);
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "limit"))
- return_limit(ptr, limit_bw, limit_pdu, limit_req);
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "target-timeout"))
- {
- const char *t = get_text(ptr);
- if (t)
- {
- *target_idletime = atoi(t);
- if (*target_idletime < 0)
- *target_idletime = 0;
- }
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "client-timeout"))
- {
- const char *t = get_text(ptr);
- if (t)
- {
- *client_idletime = atoi(t);
- if (*client_idletime < 0)
- *client_idletime = 0;
- }
- }
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "cql2rpn"))
- {
- const char *t = get_text(ptr);
- if (t)
- *cql2rpn = t;
- }
- }
-}
-#endif
-
-int Yaz_ProxyConfig::atoi_l(const char **cp)
-{
- int v = 0;
- while (**cp && isdigit(**cp))
- {
- v = v*10 + (**cp - '0');
- (*cp)++;
- }
- return v;
-}
-
-int Yaz_ProxyConfig::match_list(int v, const char *m)
-{
- while(m && *m)
- {
- while(*m && isspace(*m))
- m++;
- if (*m == '*')
- return 1;
- int l = atoi_l(&m);
- int h = l;
- if (*m == '-')
- {
- ++m;
- h = atoi_l(&m);
- }
- if (v >= l && v <= h)
- return 1;
- if (*m == ',')
- m++;
- }
- return 0;
-}
-
-#if HAVE_XSLT
-int Yaz_ProxyConfig::check_type_1_attributes(ODR odr, xmlNodePtr ptrl,
- Z_AttributeList *attrs,
- char **addinfo)
-{
- int i;
- for (i = 0; i<attrs->num_attributes; i++)
- {
- Z_AttributeElement *el = attrs->attributes[i];
-
- if (!el->attributeType)
- continue;
- int type = *el->attributeType;
- int *value = 0;
-
- if (el->which == Z_AttributeValue_numeric && el->value.numeric)
- value = el->value.numeric;
-
- xmlNodePtr ptr;
- for(ptr = ptrl->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "attribute"))
- {
- const char *match_type = 0;
- const char *match_value = 0;
- const char *match_error = 0;
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- {
- if (!strcmp((const char *) attr->name, "type") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_type = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "value") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_value = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "error") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_error = (const char *) attr->children->content;
- }
- if (match_type && match_value)
- {
- char addinfo_str[20];
- if (!match_list(type, match_type))
- continue;
-
- *addinfo_str = '\0';
- if (!strcmp(match_type, "*"))
- sprintf (addinfo_str, "%d", type);
- else if (value)
- {
- if (!match_list(*value, match_value))
- continue;
- sprintf (addinfo_str, "%d", *value);
- }
- else
- continue;
-
- if (match_error)
- {
- if (*addinfo_str)
- *addinfo = odr_strdup(odr, addinfo_str);
- return atoi(match_error);
- }
- break;
- }
- }
- }
- }
- return 0;
-}
-#endif
-
-#if HAVE_XSLT
-int Yaz_ProxyConfig::check_type_1_structure(ODR odr, xmlNodePtr ptr,
- Z_RPNStructure *q,
- char **addinfo)
-{
- if (q->which == Z_RPNStructure_complex)
- {
- int e = check_type_1_structure(odr, ptr, q->u.complex->s1, addinfo);
- if (e)
- return e;
- e = check_type_1_structure(odr, ptr, q->u.complex->s2, addinfo);
- return e;
- }
- else if (q->which == Z_RPNStructure_simple)
- {
- if (q->u.simple->which == Z_Operand_APT)
- {
- return check_type_1_attributes(
- odr, ptr, q->u.simple->u.attributesPlusTerm->attributes,
- addinfo);
- }
- }
- return 0;
-}
-#endif
-
-#if HAVE_XSLT
-int Yaz_ProxyConfig::check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query,
- char **addinfo)
-{
- // possibly check for Bib-1
- return check_type_1_structure(odr, ptr, query->RPNStructure, addinfo);
-}
-#endif
-
-int Yaz_ProxyConfig::check_query(ODR odr, const char *name, Z_Query *query,
- char **addinfo)
-{
-#if HAVE_XSLT
- xmlNodePtr ptr;
-
- ptr = find_target_node(name, 0);
- if (ptr)
- {
- if (query->which == Z_Query_type_1 || query->which == Z_Query_type_101)
- return check_type_1(odr, ptr, query->u.type_1, addinfo);
- }
-#endif
- return 0;
-}
-
-#if HAVE_XSLT
-int Yaz_ProxyConfig::check_schema(xmlNodePtr ptr, Z_RecordComposition *comp,
- const char *schema_identifier)
-{
- char *esn = 0;
- int default_match = 1;
- if (comp && comp->which == Z_RecordComp_simple &&
- comp->u.simple && comp->u.simple->which == Z_ElementSetNames_generic)
- {
- esn = comp->u.simple->u.generic;
- }
- // if no ESN/schema was given accept..
- if (!esn)
- return 1;
- // check if schema identifier match
- if (schema_identifier && !strcmp(esn, schema_identifier))
- return 1;
- // Check each name element
- for (; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "name"))
- {
- xmlNodePtr tptr = ptr->children;
- default_match = 0;
- for (; tptr; tptr = tptr->next)
- if (tptr->type == XML_TEXT_NODE && tptr->content)
- {
- xmlChar *t = tptr->content;
- while (*t && isspace(*t))
- t++;
- int i = 0;
- while (esn[i] && esn[i] == t[i])
- i++;
- if (!esn[i] && (!t[i] || isspace(t[i])))
- return 1;
- }
- }
- }
- return default_match;
-}
-#endif
-
-int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name,
- Odr_oid *syntax, Z_RecordComposition *comp,
- char **addinfo,
- char **stylesheet, char **schema)
-{
- if (stylesheet)
- {
- xfree (*stylesheet);
- *stylesheet = 0;
- }
- if (schema)
- {
- xfree (*schema);
- *schema = 0;
- }
-#if HAVE_XSLT
- int syntax_has_matched = 0;
- xmlNodePtr ptr;
-
- ptr = find_target_node(name, 0);
- if (!ptr)
- return 0;
- for(ptr = ptr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "syntax"))
- {
- int match = 0; // if we match record syntax
- const char *match_type = 0;
- const char *match_error = 0;
- const char *match_marcxml = 0;
- const char *match_stylesheet = 0;
- const char *match_identifier = 0;
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- {
- if (!strcmp((const char *) attr->name, "type") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_type = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "error") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_error = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "marcxml") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_marcxml = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "stylesheet") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_stylesheet = (const char *) attr->children->content;
- if (!strcmp((const char *) attr->name, "identifier") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- match_identifier = (const char *) attr->children->content;
- }
- if (match_type)
- {
- if (!strcmp(match_type, "*"))
- match = 1;
- else if (!strcmp(match_type, "none"))
- {
- if (syntax == 0)
- match = 1;
- }
- else if (syntax)
- {
- int match_oid[OID_SIZE];
- oid_name_to_oid(CLASS_RECSYN, match_type, match_oid);
- if (oid_oidcmp(match_oid, syntax) == 0)
- match = 1;
- }
- }
- if (match)
- {
- if (!match_error)
- syntax_has_matched = 1;
- match = check_schema(ptr->children, comp, match_identifier);
- }
- if (match)
- {
- if (stylesheet && match_stylesheet)
- {
- xfree(*stylesheet);
- *stylesheet = xstrdup(match_stylesheet);
- }
- if (schema && match_identifier)
- {
- xfree(*schema);
- *schema = xstrdup(match_identifier);
- }
- if (match_marcxml)
- {
- return -1;
- }
- if (match_error)
- {
- if (syntax_has_matched) // if syntax OK, bad schema/ESN
- return 25;
- if (syntax)
- {
- char dotoid_str[100];
- oid_to_dotstring(syntax, dotoid_str);
- *addinfo = odr_strdup(odr, dotoid_str);
- }
- return atoi(match_error);
- }
- return 0;
- }
- }
- }
-#endif
- return 0;
-}
-
-#if HAVE_XSLT
-xmlNodePtr Yaz_ProxyConfig::find_target_db(xmlNodePtr ptr, const char *db)
-{
- xmlNodePtr dptr;
- if (!db)
- return ptr;
- if (!ptr)
- return 0;
- for (dptr = ptr->children; dptr; dptr = dptr->next)
- if (dptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) dptr->name, "database"))
- {
- struct _xmlAttr *attr;
- for (attr = dptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *) attr->name, "name"))
- {
- if (attr->children
- && attr->children->type==XML_TEXT_NODE
- && attr->children->content
- && (!strcmp((const char *) attr->children->content, db)
- || !strcmp((const char *) attr->children->content,
- "*")))
- return dptr;
- }
- }
- return ptr;
-}
-
-xmlNodePtr Yaz_ProxyConfig::find_target_node(const char *name, const char *db)
-{
- xmlNodePtr ptr;
- if (!m_proxyPtr)
- return 0;
- for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "target"))
- {
- // default one ?
- if (!name)
- {
- // <target default="1"> ?
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *) attr->name, "default") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- {
- xmlChar *t = attr->children->content;
- if (!t || *t == '1')
- {
- return find_target_db(ptr, db);
- }
- }
- }
- else
- {
- // <target name="name"> ?
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *) attr->name, "name"))
- {
- if (attr->children
- && attr->children->type==XML_TEXT_NODE
- && attr->children->content
- && (!strcmp((const char *) attr->children->content,
- name)
- || !strcmp((const char *) attr->children->content,
- "*")))
- {
- return find_target_db(ptr, db);
- }
- }
- }
- }
- }
- return 0;
-}
-#endif
-
-int Yaz_ProxyConfig::get_target_no(int no,
- const char **name,
- const char **url,
- int *limit_bw,
- int *limit_pdu,
- int *limit_req,
- int *target_idletime,
- int *client_idletime,
- int *max_clients,
- int *keepalive_limit_bw,
- int *keepalive_limit_pdu,
- int *pre_init,
- const char **cql2rpn)
-{
-#if HAVE_XSLT
- xmlNodePtr ptr;
- if (!m_proxyPtr)
- return 0;
- int i = 0;
- for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "target"))
- {
- if (i == no)
- {
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *) attr->name, "name"))
- {
- if (attr->children
- && attr->children->type==XML_TEXT_NODE
- && attr->children->content)
- *name = (const char *) attr->children->content;
- }
- return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
- target_idletime, client_idletime,
- keepalive_limit_bw, keepalive_limit_pdu,
- pre_init, cql2rpn);
- return 1;
- }
- i++;
- }
-#endif
- return 0;
-}
-
-int Yaz_ProxyConfig::mycmp(const char *hay, const char *item, size_t len)
-{
- if (len == strlen(item) && memcmp(hay, item, len) == 0)
- return 1;
- return 0;
-}
-
-void Yaz_ProxyConfig::get_generic_info(int *log_mask,
- int *max_clients)
-{
-#if HAVE_XSLT
- xmlNodePtr ptr;
- if (!m_proxyPtr)
- return;
- for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE
- && !strcmp((const char *) ptr->name, "log"))
- {
- const char *v = get_text(ptr);
- *log_mask = 0;
- while (v && *v)
- {
- const char *cp = v;
- while (*cp && *cp != ',' && !isspace(*cp))
- cp++;
- size_t len = cp - v;
- if (mycmp(v, "client-apdu", len))
- *log_mask |= PROXY_LOG_APDU_CLIENT;
- if (mycmp(v, "server-apdu", len))
- *log_mask |= PROXY_LOG_APDU_SERVER;
- if (mycmp(v, "client-requests", len))
- *log_mask |= PROXY_LOG_REQ_CLIENT;
- if (mycmp(v, "server-requests", len))
- *log_mask |= PROXY_LOG_REQ_SERVER;
- if (isdigit(*v))
- *log_mask |= atoi(v);
- if (*cp == ',')
- cp++;
- while (*cp && isspace(*cp))
- cp++;
- v = cp;
- }
- }
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "max-clients"))
- {
- const char *t = get_text(ptr);
- if (t)
- {
- *max_clients = atoi(t);
- if (*max_clients < 1)
- *max_clients = 1;
- }
- }
- }
-#endif
-}
-
-char *Yaz_ProxyConfig::get_explain(ODR odr, const char *name, const char *db,
- int *len)
-{
-#if HAVE_XSLT
- xmlNodePtr ptr = find_target_node(name, db);
- if (ptr)
- {
- ptr = ptr->children;
- for (; ptr; ptr = ptr->next)
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "explain"))
- {
- xmlNodePtr ptr1 = ptr->children;
- if (db)
- {
- for (; ptr1; ptr1 = ptr1->next)
- if (ptr1->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr1->name, "serverInfo"))
- break;
- if (!ptr1)
- continue;
- for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
- if (ptr1->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr1->name, "database"))
- break;
-
- if (!ptr1)
- continue;
- for (ptr1 = ptr1->children; ptr1; ptr1 = ptr1->next)
- if (ptr1->type == XML_TEXT_NODE &&
- ptr1->content &&
- !strcmp((const char *) ptr1->content, db))
- break;
- if (!ptr1)
- continue;
- }
- xmlNodePtr ptr2 = xmlCopyNode(ptr, 1);
-
- xmlDocPtr doc = xmlNewDoc((const xmlChar *) "1.0");
-
- xmlDocSetRootElement(doc, ptr2);
-
- xmlChar *buf_out;
- xmlDocDumpMemory(doc, &buf_out, len);
- char *content = (char*) odr_malloc(odr, *len);
- memcpy(content, buf_out, *len);
-
- xmlFree(buf_out);
- xmlFreeDoc(doc);
- return content;
- }
- }
-#endif
- return 0;
-}
-
-void Yaz_ProxyConfig::get_target_info(const char *name,
- const char **url,
- int *limit_bw,
- int *limit_pdu,
- int *limit_req,
- int *target_idletime,
- int *client_idletime,
- int *max_clients,
- int *keepalive_limit_bw,
- int *keepalive_limit_pdu,
- int *pre_init,
- const char **cql2rpn)
-{
-#if HAVE_XSLT
- xmlNodePtr ptr;
- if (!m_proxyPtr)
- {
- url[0] = name;
- url[1] = 0;
- return;
- }
- url[0] = 0;
- for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE &&
- !strcmp((const char *) ptr->name, "max-clients"))
- {
- const char *t = get_text(ptr);
- if (t)
- {
- *max_clients = atoi(t);
- if (*max_clients < 1)
- *max_clients = 1;
- }
- }
- }
- ptr = find_target_node(name, 0);
- if (ptr)
- {
- if (name)
- {
- url[0] = name;
- url[1] = 0;
- }
- return_target_info(ptr, url, limit_bw, limit_pdu, limit_req,
- target_idletime, client_idletime,
- keepalive_limit_bw, keepalive_limit_pdu,
- pre_init, cql2rpn);
- }
-#else
- *url = name;
- return;
-#endif
-}
-
-
+++ /dev/null
-/*
- * Copyright (c) 1998-2004, Index Data.
- * See the file LICENSE for details.
- *
- * $Id: yaz-proxy-main.cpp,v 1.35 2004-03-17 10:49:58 adam Exp $
- */
-
-#include <signal.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <sys/types.h>
-#include <stdarg.h>
-
-#if HAVE_GETRLIMIT
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
-
-#include <yaz/log.h>
-#include <yaz/options.h>
-
-#include <yaz++/socket-manager.h>
-#include <yaz++/pdu-assoc.h>
-#include <yaz++/proxy.h>
-
-void usage(char *prog)
-{
- fprintf (stderr, "%s: [-c config] [-l log] [-a log] [-v level] [-t target] "
- "[-u uid] [-p pidfile] @:port\n", prog);
- exit (1);
-}
-
-static char *pid_fname = 0;
-static char *uid = 0;
-static char *log_file = 0;
-static int debug = 0;
-static int no_limit_files = 0;
-
-int args(Yaz_Proxy *proxy, int argc, char **argv)
-{
- char *addr = 0;
- char *arg;
- char *prog = argv[0];
- int ret;
-
- while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:U:n:X",
- argv, argc, &arg)) != -2)
- {
- int err;
- switch (ret)
- {
- case 0:
- if (addr)
- {
- usage(prog);
- return 1;
- }
- addr = arg;
- break;
- case 'c':
- err = proxy->set_config(arg);
- if (err == -2)
- {
- fprintf(stderr, "Config file support not enabled (proxy not compiled with libxml2 support)\n");
- exit(1);
- }
- else if (err == -1)
- {
- fprintf(stderr, "Bad or missing file %s\n", arg);
- exit(1);
- }
- break;
- case 'a':
- proxy->set_APDU_log(arg);
- break;
- case 't':
- proxy->set_default_target(arg);
- break;
- case 'U':
- proxy->set_proxy_authentication(arg);
- break;
- case 'o':
- proxy->option("optimize", arg);
- break;
- case 'v':
- yaz_log_init_level (yaz_log_mask_str(arg));
- break;
- case 'l':
- yaz_log_init_file (arg);
- log_file = xstrdup(arg);
- break;
- case 'm':
- proxy->set_max_clients(atoi(arg));
- break;
- case 'i':
- proxy->set_client_idletime(atoi(arg));
- break;
- case 'T':
- proxy->set_target_idletime(atoi(arg));
- break;
- case 'n':
- no_limit_files = atoi(arg);
- break;
- case 'X':
- debug = 1;
- break;
- case 'p':
- if (!pid_fname)
- pid_fname = xstrdup(arg);
- break;
- case 'u':
- if (!uid)
- uid = xstrdup(arg);
- break;
- default:
- usage(prog);
- return 1;
- }
- }
- if (addr)
- {
- if (proxy->server(addr))
- {
- yaz_log(LOG_FATAL|LOG_ERRNO, "listen %s", addr);
- exit(1);
- }
- }
- else
- {
- usage(prog);
- return 1;
- }
- return 0;
-}
-
-static Yaz_Proxy *static_yaz_proxy = 0;
-static void sighup_handler(int num)
-{
- signal(SIGHUP, sighup_handler);
- if (static_yaz_proxy)
- static_yaz_proxy->reconfig();
-}
-
-#if HAVE_XSLT
-static void proxy_xml_error_handler(void *ctx, const char *fmt, ...)
-{
- char buf[1024];
-
- va_list ap;
- va_start(ap, fmt);
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
-
- yaz_log(LOG_WARN, "%s: %s", (char*) ctx, buf);
-
- va_end (ap);
-}
-#endif
-
-static void child_run(Yaz_SocketManager *m, int run)
-{
- signal(SIGHUP, sighup_handler);
-
-#if HAVE_XSLT
- xmlSetGenericErrorFunc((void *) "XML", proxy_xml_error_handler);
- xsltSetGenericErrorFunc((void *) "XSLT", proxy_xml_error_handler);
-#endif
- yaz_log(LOG_LOG, "0 proxy run=%d pid=%ld", run, (long) getpid());
-
- if (no_limit_files)
- {
-#if HAVE_SETRLIMIT
- struct rlimit limit_data;
- limit_data.rlim_cur = no_limit_files;
- limit_data.rlim_max = no_limit_files;
-
- yaz_log(LOG_LOG, "0 setrlimit NOFILE cur=%d max=%d",
- limit_data.rlim_cur, limit_data.rlim_max);
- if (setrlimit(RLIMIT_NOFILE, &limit_data))
- yaz_log(LOG_ERRNO|LOG_WARN, "setrlimit");
-#else
- yaz_log(LOG_WARN, "setrlimit unavablable. Option -n ignored");
-#endif
- }
- if (pid_fname)
- {
- FILE *f = fopen(pid_fname, "w");
- if (!f)
- {
- yaz_log(LOG_ERRNO|LOG_FATAL, "Couldn't create %s", pid_fname);
- exit(0);
- }
- fprintf(f, "%ld", (long) getpid());
- fclose(f);
- xfree(pid_fname);
- }
- if (uid)
- {
- struct passwd *pw;
-
- if (!(pw = getpwnam(uid)))
- {
- yaz_log(LOG_FATAL, "%s: Unknown user", uid);
- exit(3);
- }
- if (log_file)
- {
- chown(log_file, pw->pw_uid, pw->pw_gid);
- xfree(log_file);
- }
- if (setuid(pw->pw_uid) < 0)
- {
- yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
- exit(4);
- }
- xfree(uid);
- }
-#if HAVE_GETRLIMIT
- struct rlimit limit_data;
- getrlimit(RLIMIT_NOFILE, &limit_data);
- yaz_log(LOG_LOG, "0 getrlimit NOFILE cur=%d max=%d",
- limit_data.rlim_cur, limit_data.rlim_max);
-#endif
-
- while (m->processEvent() > 0)
- ;
-
- exit (0);
-}
-
-int main(int argc, char **argv)
-{
-#if HAVE_XSLT
- xmlInitMemory();
-
- LIBXML_TEST_VERSION
-#endif
- int cont = 1;
- int run = 1;
- Yaz_SocketManager mySocketManager;
- Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
-
- static_yaz_proxy = &proxy;
-
- args(&proxy, argc, argv);
-
- if (debug)
- {
- child_run(&mySocketManager, run);
- exit(0);
- }
- while (cont)
- {
- pid_t p = fork();
- if (p == (pid_t) -1)
- {
- yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
- exit(1);
- }
- else if (p == 0)
- {
- child_run(&mySocketManager, run);
- }
- pid_t p1;
- int status;
- p1 = wait(&status);
-
- yaz_log_reopen();
-
- if (p1 != p)
- {
- yaz_log(LOG_FATAL, "p1=%d != p=%d", p1, p);
- exit(1);
- }
- if (WIFSIGNALED(status))
- {
- switch(WTERMSIG(status)) {
- case SIGILL:
- yaz_log(LOG_WARN, "Received SIGILL from child %ld", (long) p);
- cont = 1;
- break;
- case SIGABRT:
- yaz_log(LOG_WARN, "Received SIGABRT from child %ld", (long) p);
- cont = 1;
- break ;
- case SIGSEGV:
- yaz_log(LOG_WARN, "Received SIGSEGV from child %ld", (long) p);
- cont = 1;
- break;
- case SIGBUS:
- yaz_log(LOG_WARN, "Received SIGBUS from child %ld", (long) p);
- cont = 1;
- break;
- case SIGTERM:
- yaz_log(LOG_LOG, "Received SIGTERM from child %ld",
- (long) p);
- cont = 0;
- break;
- default:
- yaz_log(LOG_WARN, "Received SIG %d from child %ld",
- WTERMSIG(status), (long) p);
- cont = 0;
- }
- }
- else if (status == 0)
- cont = 0;
- else
- {
- yaz_log(LOG_LOG, "Exit %d from child %ld", status, (long) p);
- cont = 1;
- }
- if (cont)
- sleep(1 + run/5);
- run++;
- }
- exit (0);
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (c) 1998-2004, Index Data.
- * See the file LICENSE for details.
- *
- * $Id: yaz-proxy.cpp,v 1.110 2004-03-17 10:49:22 adam Exp $
- */
-
-#include <unistd.h>
-#include <assert.h>
-#include <time.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <yaz/srw.h>
-#include <yaz/marcdisp.h>
-#include <yaz/yaz-iconv.h>
-#include <yaz/log.h>
-#include <yaz/diagbib1.h>
-#include <yaz++/proxy.h>
-#include <yaz/pquery.h>
-
-static const char *apdu_name(Z_APDU *apdu)
-{
- switch (apdu->which)
- {
- case Z_APDU_initRequest:
- return "initRequest";
- case Z_APDU_initResponse:
- return "initResponse";
- case Z_APDU_searchRequest:
- return "searchRequest";
- case Z_APDU_searchResponse:
- return "searchResponse";
- case Z_APDU_presentRequest:
- return "presentRequest";
- case Z_APDU_presentResponse:
- return "presentResponse";
- case Z_APDU_deleteResultSetRequest:
- return "deleteResultSetRequest";
- case Z_APDU_deleteResultSetResponse:
- return "deleteResultSetResponse";
- case Z_APDU_scanRequest:
- return "scanRequest";
- case Z_APDU_scanResponse:
- return "scanResponse";
- case Z_APDU_sortRequest:
- return "sortRequest";
- case Z_APDU_sortResponse:
- return "sortResponse";
- case Z_APDU_extendedServicesRequest:
- return "extendedServicesRequest";
- case Z_APDU_extendedServicesResponse:
- return "extendedServicesResponse";
- case Z_APDU_close:
- return "close";
- }
- return "other";
-}
-
-static const char *gdu_name(Z_GDU *gdu)
-{
- switch(gdu->which)
- {
- case Z_GDU_Z3950:
- return apdu_name(gdu->u.z3950);
- case Z_GDU_HTTP_Request:
- return "HTTP Request";
- case Z_GDU_HTTP_Response:
- return "HTTP Response";
- }
- return "Unknown request/response";
-}
-
-Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable,
- Yaz_Proxy *parent) :
- Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60)
-{
- m_PDU_Observable = the_PDU_Observable;
- m_client = 0;
- m_parent = parent;
- m_clientPool = 0;
- m_seqno = 1;
- m_keepalive_limit_bw = 500000;
- m_keepalive_limit_pdu = 1000;
- m_proxyTarget = 0;
- m_default_target = 0;
- m_proxy_authentication = 0;
- m_max_clients = 150;
- m_log_mask = 0;
- m_seed = time(0);
- m_client_idletime = 600;
- m_target_idletime = 600;
- m_optimize = xstrdup ("1");
- strcpy(m_session_str, "0 ");
- m_session_no=0;
- m_bytes_sent = 0;
- m_bytes_recv = 0;
- m_bw_hold_PDU = 0;
- m_bw_max = 0;
- m_pdu_max = 0;
- m_max_record_retrieve = 0;
- m_reconfig_flag = 0;
- m_config_fname = 0;
- m_request_no = 0;
- m_invalid_session = 0;
- m_referenceId = 0;
- m_referenceId_mem = nmem_create();
- m_config = 0;
- m_marcxml_flag = 0;
- m_stylesheet_xsp = 0;
- m_stylesheet_nprl = 0;
- m_s2z_stylesheet = 0;
- m_s2z_database = 0;
- m_schema = 0;
- m_initRequest_apdu = 0;
- m_initRequest_mem = 0;
- m_initRequest_preferredMessageSize = 0;
- m_initRequest_maximumRecordSize = 0;
- m_initRequest_options = 0;
- m_initRequest_version = 0;
- m_apdu_invalid_session = 0;
- m_mem_invalid_session = 0;
- m_s2z_odr_init = 0;
- m_s2z_odr_search = 0;
- m_s2z_init_apdu = 0;
- m_s2z_search_apdu = 0;
- m_s2z_present_apdu = 0;
- m_http_keepalive = 0;
- m_http_version = 0;
- m_soap_ns = 0;
- m_s2z_packing = Z_SRW_recordPacking_string;
- m_time_tv.tv_sec = 0;
- m_time_tv.tv_usec = 0;
- if (!m_parent)
- low_socket_open();
-}
-
-Yaz_Proxy::~Yaz_Proxy()
-{
- yaz_log(LOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str,
- m_bytes_sent, m_bytes_recv);
- nmem_destroy(m_initRequest_mem);
- nmem_destroy(m_mem_invalid_session);
- nmem_destroy(m_referenceId_mem);
-
- xfree (m_proxyTarget);
- xfree (m_default_target);
- xfree (m_proxy_authentication);
- xfree (m_optimize);
-
- if (m_stylesheet_xsp)
- xsltFreeStylesheet(m_stylesheet_xsp);
-
- xfree (m_schema);
- if (m_s2z_odr_init)
- odr_destroy(m_s2z_odr_init);
- if (m_s2z_odr_search)
- odr_destroy(m_s2z_odr_search);
- if (!m_parent)
- low_socket_close();
- delete m_config;
-}
-
-int Yaz_Proxy::set_config(const char *config)
-{
- delete m_config;
- m_config = new Yaz_ProxyConfig();
- xfree(m_config_fname);
- m_config_fname = xstrdup(config);
- int r = m_config->read_xml(config);
- if (!r)
- m_config->get_generic_info(&m_log_mask, &m_max_clients);
- return r;
-}
-
-void Yaz_Proxy::set_default_target(const char *target)
-{
- xfree (m_default_target);
- m_default_target = 0;
- if (target)
- m_default_target = (char *) xstrdup (target);
-}
-
-void Yaz_Proxy::set_proxy_authentication (const char *auth)
-{
- xfree (m_proxy_authentication);
- m_proxy_authentication = 0;
- if (auth)
- m_proxy_authentication = (char *) xstrdup (auth);
-}
-
-Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure()
-{
- if (m_parent)
- return m_parent->check_reconfigure();
-
- Yaz_ProxyConfig *cfg = m_config;
- if (m_reconfig_flag)
- {
- yaz_log(LOG_LOG, "reconfigure");
- yaz_log_reopen();
- if (m_config_fname && cfg)
- {
- yaz_log(LOG_LOG, "reconfigure config %s", m_config_fname);
- int r = cfg->read_xml(m_config_fname);
- if (r)
- yaz_log(LOG_WARN, "reconfigure failed");
- else
- {
- m_log_mask = 0;
- cfg->get_generic_info(&m_log_mask, &m_max_clients);
- }
- }
- else
- yaz_log(LOG_LOG, "reconfigure");
- m_reconfig_flag = 0;
- }
- return cfg;
-}
-
-IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable
- *the_PDU_Observable, int fd)
-{
- check_reconfigure();
- Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable, this);
- new_proxy->m_config = 0;
- new_proxy->m_config_fname = 0;
- new_proxy->timeout(m_client_idletime);
- new_proxy->m_target_idletime = m_target_idletime;
- new_proxy->set_default_target(m_default_target);
- new_proxy->m_max_clients = m_max_clients;
- new_proxy->m_log_mask = m_log_mask;
- new_proxy->set_APDU_log(get_APDU_log());
- if (m_log_mask & PROXY_LOG_APDU_CLIENT)
- new_proxy->set_APDU_yazlog(1);
- else
- new_proxy->set_APDU_yazlog(0);
- new_proxy->set_proxy_authentication(m_proxy_authentication);
- sprintf(new_proxy->m_session_str, "%ld:%d ", (long) time(0), m_session_no);
- m_session_no++;
- yaz_log (LOG_LOG, "%sNew session %s", new_proxy->m_session_str,
- the_PDU_Observable->getpeername());
- return new_proxy;
-}
-
-char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
-{
- int oid[OID_SIZE];
- Z_OtherInformationUnit *oi;
- struct oident ent;
- ent.proto = PROTO_Z3950;
- ent.oclass = CLASS_USERINFO;
- ent.value = (oid_value) VAL_COOKIE;
- assert (oid_ent_to_oid (&ent, oid));
-
- if (oid_ent_to_oid (&ent, oid) &&
- (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
- oi->which == Z_OtherInfo_characterInfo)
- return oi->information.characterInfo;
- return 0;
-}
-
-char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
-{
- int oid[OID_SIZE];
- Z_OtherInformationUnit *oi;
- struct oident ent;
- ent.proto = PROTO_Z3950;
- ent.oclass = CLASS_USERINFO;
- ent.value = (oid_value) VAL_PROXY;
- if (oid_ent_to_oid (&ent, oid) &&
- (oi = update_otherInformation(otherInfo, 0, oid, 1, 1)) &&
- oi->which == Z_OtherInfo_characterInfo)
- return oi->information.characterInfo;
- return 0;
-}
-
-const char *Yaz_Proxy::load_balance(const char **url)
-{
- int zurl_in_use[MAX_ZURL_PLEX];
- int zurl_in_spare[MAX_ZURL_PLEX];
- Yaz_ProxyClient *c;
- int i;
-
- for (i = 0; i<MAX_ZURL_PLEX; i++)
- {
- zurl_in_use[i] = 0;
- zurl_in_spare[i] = 0;
- }
- for (c = m_parent->m_clientPool; c; c = c->m_next)
- {
- for (i = 0; url[i]; i++)
- if (!strcmp(url[i], c->get_hostname()))
- {
- zurl_in_use[i]++;
- if (c->m_cookie == 0 && c->m_server == 0 && c->m_waiting == 0)
- zurl_in_spare[i]++;
- }
- }
- int min_use = 100000;
- int spare_for_min = 0;
- int max_spare = 0;
- const char *ret_min = 0;
- const char *ret_spare = 0;
- for (i = 0; url[i]; i++)
- {
- yaz_log(LOG_DEBUG, "%szurl=%s use=%d spare=%d",
- m_session_str, url[i], zurl_in_use[i], zurl_in_spare[i]);
- if (min_use > zurl_in_use[i])
- {
- ret_min = url[i];
- min_use = zurl_in_use[i];
- spare_for_min = zurl_in_spare[i];
- }
- if (max_spare < zurl_in_spare[i])
- {
- ret_spare = url[i];
- max_spare = zurl_in_spare[i];
- }
- }
- // use the one with minimum connections if spare is > 3
- if (spare_for_min > 3)
- return ret_min;
- // use one with most spares (if any)
- if (max_spare > 0)
- return ret_spare;
- return ret_min;
-}
-
-Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie,
- const char *proxy_host)
-{
- assert (m_parent);
- Yaz_Proxy *parent = m_parent;
- Yaz_ProxyClient *c = m_client;
-
- if (!m_proxyTarget)
- {
- const char *url[MAX_ZURL_PLEX];
- Yaz_ProxyConfig *cfg = check_reconfigure();
- if (proxy_host)
- {
-#if 1
-/* only to be enabled for debugging... */
- if (!strcmp(proxy_host, "stop"))
- exit(0);
-#endif
- xfree(m_default_target);
- m_default_target = xstrdup(proxy_host);
- proxy_host = m_default_target;
- }
- int client_idletime = -1;
- const char *cql2rpn_fname = 0;
- url[0] = m_default_target;
- url[1] = 0;
- if (cfg)
- {
- int pre_init = 0;
- cfg->get_target_info(proxy_host, url, &m_bw_max,
- &m_pdu_max, &m_max_record_retrieve,
- &m_target_idletime, &client_idletime,
- &parent->m_max_clients,
- &m_keepalive_limit_bw,
- &m_keepalive_limit_pdu,
- &pre_init,
- &cql2rpn_fname);
- }
- if (client_idletime != -1)
- {
- m_client_idletime = client_idletime;
- timeout(m_client_idletime);
- }
- if (cql2rpn_fname)
- m_cql2rpn.set_pqf_file(cql2rpn_fname);
- if (!url[0])
- {
- yaz_log(LOG_LOG, "%sNo default target", m_session_str);
- return 0;
- }
- // we don't handle multiplexing for cookie session, so we just
- // pick the first one in this case (anonymous users will be able
- // to use any backend)
- if (cookie && *cookie)
- m_proxyTarget = (char*) xstrdup(url[0]);
- else
- m_proxyTarget = (char*) xstrdup(load_balance(url));
- }
- if (cookie && *cookie)
- { // search in sessions with a cookie
- for (c = parent->m_clientPool; c; c = c->m_next)
- {
- assert (c->m_prev);
- assert (*c->m_prev == c);
- if (c->m_cookie && !strcmp(cookie,c->m_cookie) &&
- !strcmp(m_proxyTarget, c->get_hostname()))
- {
- // Found it in cache
- // The following handles "cancel"
- // If connection is busy (waiting for PDU) and
- // we have an initRequest we can safely do re-open
- if (c->m_waiting && apdu->which == Z_APDU_initRequest)
- {
- yaz_log (LOG_LOG, "%s REOPEN target=%s", m_session_str,
- c->get_hostname());
- c->close();
- c->m_init_flag = 0;
-
- c->m_last_ok = 0;
- c->m_cache.clear();
- c->m_last_resultCount = 0;
- c->m_sr_transform = 0;
- c->m_waiting = 0;
- c->m_resultSetStartPoint = 0;
- c->m_target_idletime = m_target_idletime;
- if (c->client(m_proxyTarget))
- {
- delete c;
- return 0;
- }
- c->timeout(30);
- }
- c->m_seqno = parent->m_seqno;
- if (c->m_server && c->m_server != this)
- c->m_server->m_client = 0;
- c->m_server = this;
- (parent->m_seqno)++;
- yaz_log (LOG_DEBUG, "get_client 1 %p %p", this, c);
- return c;
- }
- }
- }
- else if (!c)
- {
- // don't have a client session yet. Search in session w/o cookie
- for (c = parent->m_clientPool; c; c = c->m_next)
- {
- assert (c->m_prev);
- assert (*c->m_prev == c);
- if (c->m_server == 0 && c->m_cookie == 0 &&
- c->m_waiting == 0 &&
- !strcmp(m_proxyTarget, c->get_hostname()))
- {
- // found it in cache
- yaz_log (LOG_LOG, "%sREUSE %d %s",
- m_session_str, parent->m_seqno, c->get_hostname());
-
- c->m_seqno = parent->m_seqno;
- assert(c->m_server == 0);
- c->m_server = this;
-
- if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
- c->set_APDU_yazlog(1);
- else
- c->set_APDU_yazlog(0);
-
- (parent->m_seqno)++;
-
- parent->pre_init();
-
- return c;
- }
- }
- }
- if (!m_client)
- {
- if (apdu->which != Z_APDU_initRequest)
- {
- yaz_log (LOG_LOG, "%sno init request as first PDU", m_session_str);
- return 0;
- }
- Z_InitRequest *initRequest = apdu->u.initRequest;
-
- if (!initRequest->idAuthentication)
- {
- if (m_proxy_authentication)
- {
- initRequest->idAuthentication =
- (Z_IdAuthentication *)
- odr_malloc (odr_encode(),
- sizeof(*initRequest->idAuthentication));
- initRequest->idAuthentication->which =
- Z_IdAuthentication_open;
- initRequest->idAuthentication->u.open =
- odr_strdup (odr_encode(), m_proxy_authentication);
- }
- }
- // go through list of clients - and find the lowest/oldest one.
- Yaz_ProxyClient *c_min = 0;
- int min_seq = -1;
- int no_of_clients = 0;
- if (parent->m_clientPool)
- yaz_log (LOG_DEBUG, "Existing sessions");
- for (c = parent->m_clientPool; c; c = c->m_next)
- {
- yaz_log (LOG_DEBUG, " Session %-3d wait=%d %s cookie=%s", c->m_seqno,
- c->m_waiting, c->get_hostname(),
- c->m_cookie ? c->m_cookie : "");
- no_of_clients++;
- if (min_seq < 0 || c->m_seqno < min_seq)
- {
- min_seq = c->m_seqno;
- c_min = c;
- }
- }
- if (no_of_clients >= parent->m_max_clients)
- {
- c = c_min;
- if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname()))
- {
- yaz_log (LOG_LOG, "%sMAXCLIENTS %d Destroy %d",
- m_session_str, parent->m_max_clients, c->m_seqno);
- if (c->m_server && c->m_server != this)
- delete c->m_server;
- c->m_server = 0;
- }
- else
- {
- yaz_log (LOG_LOG, "%sMAXCLIENTS %d Reuse %d %d %s",
- m_session_str, parent->m_max_clients,
- c->m_seqno, parent->m_seqno, c->get_hostname());
- xfree (c->m_cookie);
- c->m_cookie = 0;
- if (cookie)
- c->m_cookie = xstrdup(cookie);
- c->m_seqno = parent->m_seqno;
- if (c->m_server && c->m_server != this)
- {
- c->m_server->m_client = 0;
- delete c->m_server;
- }
- (parent->m_seqno)++;
- c->m_target_idletime = m_target_idletime;
- c->timeout(m_target_idletime);
-
- if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
- c->set_APDU_yazlog(1);
- else
- c->set_APDU_yazlog(0);
-
- return c;
- }
- }
- else
- {
- yaz_log (LOG_LOG, "%sNEW %d %s",
- m_session_str, parent->m_seqno, m_proxyTarget);
- c = new Yaz_ProxyClient(m_PDU_Observable->clone(), parent);
- c->m_next = parent->m_clientPool;
- if (c->m_next)
- c->m_next->m_prev = &c->m_next;
- parent->m_clientPool = c;
- c->m_prev = &parent->m_clientPool;
- }
-
- xfree (c->m_cookie);
- c->m_cookie = 0;
- if (cookie)
- c->m_cookie = xstrdup(cookie);
-
- c->m_seqno = parent->m_seqno;
- c->m_init_flag = 0;
- c->m_last_resultCount = 0;
- c->m_last_ok = 0;
- c->m_cache.clear();
- c->m_sr_transform = 0;
- c->m_waiting = 0;
- c->m_resultSetStartPoint = 0;
- (parent->m_seqno)++;
- if (c->client(m_proxyTarget))
- {
- delete c;
- return 0;
- }
- c->m_target_idletime = m_target_idletime;
- c->timeout(30);
-
- if (parent->m_log_mask & PROXY_LOG_APDU_SERVER)
- c->set_APDU_yazlog(1);
- else
- c->set_APDU_yazlog(0);
- }
- yaz_log (LOG_DEBUG, "get_client 3 %p %p", this, c);
- return c;
-}
-
-void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num)
-{
- int i;
- for (i = 0; i<num; i++)
- {
- oident *ent;
- Z_DefaultDiagFormat *r;
- Z_DiagRec *p = pp[i];
- if (p->which != Z_DiagRec_defaultFormat)
- {
- yaz_log(LOG_LOG, "%sError no diagnostics", m_session_str);
- return;
- }
- else
- r = p->u.defaultFormat;
- if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
- ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
- yaz_log(LOG_LOG, "%sError unknown diagnostic set", m_session_str);
- switch (r->which)
- {
- case Z_DefaultDiagFormat_v2Addinfo:
- yaz_log(LOG_LOG, "%sError %d %s:%s",
- m_session_str,
- *r->condition, diagbib1_str(*r->condition),
- r->u.v2Addinfo);
- break;
- case Z_DefaultDiagFormat_v3Addinfo:
- yaz_log(LOG_LOG, "%sError %d %s:%s",
- m_session_str,
- *r->condition, diagbib1_str(*r->condition),
- r->u.v3Addinfo);
- break;
- }
- }
-}
-
-int Yaz_Proxy::convert_xsl(Z_NamePlusRecordList *p, Z_APDU *apdu)
-{
- if (!m_stylesheet_xsp || p->num_records <= 0)
- return 0; /* no XSLT to be done ... */
-
- m_stylesheet_offset = 0;
- m_stylesheet_nprl = p;
- m_stylesheet_apdu = apdu;
- timeout(0);
- return 1;
-}
-
-void Yaz_Proxy::convert_xsl_delay()
-{
- Z_NamePlusRecord *npr = m_stylesheet_nprl->records[m_stylesheet_offset];
- if (npr->which == Z_NamePlusRecord_databaseRecord)
- {
- Z_External *r = npr->u.databaseRecord;
- if (r->which == Z_External_octet)
- {
-#if 0
- fwrite((char*) r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, stdout);
-#endif
- xmlDocPtr res, doc = xmlParseMemory(
- (char*) r->u.octet_aligned->buf,
- r->u.octet_aligned->len);
-
-
- yaz_log(LOG_LOG, "%sXSLT convert %d",
- m_session_str, m_stylesheet_offset);
- res = xsltApplyStylesheet(m_stylesheet_xsp, doc, 0);
-
- if (res)
- {
- xmlChar *out_buf;
- int out_len;
- xmlDocDumpFormatMemory (res, &out_buf, &out_len, 1);
-
- m_stylesheet_nprl->records[m_stylesheet_offset]->
- u.databaseRecord =
- z_ext_record(odr_encode(), VAL_TEXT_XML,
- (char*) out_buf, out_len);
- xmlFree(out_buf);
- xmlFreeDoc(res);
- }
-
- xmlFreeDoc(doc);
- }
- }
- m_stylesheet_offset++;
- if (m_stylesheet_offset == m_stylesheet_nprl->num_records)
- {
- m_stylesheet_nprl = 0;
- if (m_stylesheet_xsp)
- xsltFreeStylesheet(m_stylesheet_xsp);
- m_stylesheet_xsp = 0;
- timeout(m_client_idletime);
- send_PDU_convert(m_stylesheet_apdu);
- }
- else
- timeout(0);
-}
-
-void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p)
-{
- int i;
-
- yaz_iconv_t cd = yaz_iconv_open("UTF-8", "MARC-8");
- yaz_marc_t mt = yaz_marc_create();
- yaz_marc_xml(mt, YAZ_MARC_MARCXML);
- yaz_marc_iconv(mt, cd);
- for (i = 0; i < p->num_records; i++)
- {
- Z_NamePlusRecord *npr = p->records[i];
- if (npr->which == Z_NamePlusRecord_databaseRecord)
- {
- Z_External *r = npr->u.databaseRecord;
- if (r->which == Z_External_octet)
- {
- int rlen;
- char *result;
- if (yaz_marc_decode_buf(mt, (char*) r->u.octet_aligned->buf,
- r->u.octet_aligned->len,
- &result, &rlen))
- {
- npr->u.databaseRecord = z_ext_record(odr_encode(),
- VAL_TEXT_XML,
- result, rlen);
- }
- }
- }
- }
- if (cd)
- yaz_iconv_close(cd);
- yaz_marc_destroy(mt);
-}
-
-void Yaz_Proxy::logtime()
-{
- if (m_time_tv.tv_sec)
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- long diff = (tv.tv_sec - m_time_tv.tv_sec)*1000000 +
- (tv.tv_usec - m_time_tv.tv_usec);
- if (diff >= 0)
- yaz_log(LOG_LOG, "%sElapsed %ld.%03ld", m_session_str,
- diff/1000000, (diff/1000)%1000);
- }
- m_time_tv.tv_sec = 0;
- m_time_tv.tv_usec = 0;
-}
-
-int Yaz_Proxy::send_http_response(int code)
-{
- ODR o = odr_encode();
- Z_GDU *gdu = z_get_HTTP_Response(o, code);
- Z_HTTP_Response *hres = gdu->u.HTTP_Response;
- if (m_http_version)
- hres->version = odr_strdup(o, m_http_version);
- if (m_http_keepalive)
- z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
- else
- timeout(0);
-
- if (m_log_mask & PROXY_LOG_REQ_CLIENT)
- {
- yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
- gdu_name(gdu));
- }
- int len;
- int r = send_GDU(gdu, &len);
- m_bytes_sent += len;
- m_bw_stat.add_bytes(len);
- logtime();
- return r;
-}
-
-int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu)
-{
- ODR o = odr_encode();
- const char *ctype = "text/xml";
- Z_GDU *gdu = z_get_HTTP_Response(o, 200);
- Z_HTTP_Response *hres = gdu->u.HTTP_Response;
- if (m_http_version)
- hres->version = odr_strdup(o, m_http_version);
- z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype);
- if (m_http_keepalive)
- z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive");
- else
- timeout(0);
-
- static Z_SOAP_Handler soap_handlers[2] = {
-#if HAVE_XSLT
- {"http://www.loc.gov/zing/srw/", 0,
- (Z_SOAP_fun) yaz_srw_codec},
-#endif
- {0, 0, 0}
- };
-
- Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP));
- soap_package->which = Z_SOAP_generic;
- soap_package->u.generic =
- (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic));
- soap_package->u.generic->no = 0;
- soap_package->u.generic->ns = soap_handlers[0].ns;
- soap_package->u.generic->p = (void *) srw_pdu;
- soap_package->ns = m_soap_ns;
- z_soap_codec_enc_xsl(o, &soap_package,
- &hres->content_buf, &hres->content_len,
- soap_handlers, 0, m_s2z_stylesheet);
- if (m_log_mask & PROXY_LOG_REQ_CLIENT)
- {
- yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
- gdu_name(gdu));
- }
- int len;
- int r = send_GDU(gdu, &len);
- m_bytes_sent += len;
- m_bw_stat.add_bytes(len);
- logtime();
- return r;
-}
-
-int Yaz_Proxy::send_to_srw_client_error(int srw_error, const char *add)
-{
- ODR o = odr_encode();
- Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
- Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
-
- srw_res->num_diagnostics = 1;
- srw_res->diagnostics = (Z_SRW_diagnostic *)
- odr_malloc(o, sizeof(*srw_res->diagnostics));
- yaz_mk_std_diagnostic(o, srw_res->diagnostics, srw_error, add);
- return send_srw_response(srw_pdu);
-}
-
-int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res,
- Z_DefaultDiagFormat *ddf)
-{
- int bib1_code = *ddf->condition;
- if (bib1_code == 109)
- return 404;
- srw_res->num_diagnostics = 1;
- srw_res->diagnostics = (Z_SRW_diagnostic *)
- odr_malloc(o, sizeof(*srw_res->diagnostics));
- yaz_mk_std_diagnostic(o, srw_res->diagnostics,
- yaz_diag_bib1_to_srw(*ddf->condition),
- ddf->u.v2Addinfo);
- return 0;
-}
-
-int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records, int start)
-{
- ODR o = odr_encode();
- Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
- Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
-
- srw_res->numberOfRecords = odr_intdup (o, hits);
- if (records && records->which == Z_Records_DBOSD)
- {
- srw_res->num_records =
- records->u.databaseOrSurDiagnostics->num_records;
- int i;
- srw_res->records = (Z_SRW_record *)
- odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record));
- for (i = 0; i < srw_res->num_records; i++)
- {
- Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i];
- if (npr->which != Z_NamePlusRecord_databaseRecord)
- {
- srw_res->records[i].recordSchema = "diagnostic";
- srw_res->records[i].recordPacking = m_s2z_packing;
- srw_res->records[i].recordData_buf = "67";
- srw_res->records[i].recordData_len = 2;
- srw_res->records[i].recordPosition = odr_intdup(o, i+start);
- continue;
- }
- Z_External *r = npr->u.databaseRecord;
- oident *ent = oid_getentbyoid(r->direct_reference);
- if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML)
- {
- srw_res->records[i].recordSchema = m_schema;
- srw_res->records[i].recordPacking = m_s2z_packing;
- srw_res->records[i].recordData_buf = (char*)
- r->u.octet_aligned->buf;
- srw_res->records[i].recordData_len = r->u.octet_aligned->len;
- srw_res->records[i].recordPosition = odr_intdup(o, i+start);
- }
- else
- {
- srw_res->records[i].recordSchema = "diagnostic";
- srw_res->records[i].recordPacking = m_s2z_packing;
- srw_res->records[i].recordData_buf = "67";
- srw_res->records[i].recordData_len = 2;
- srw_res->records[i].recordPosition = odr_intdup(o, i+start);
- }
- }
- }
- if (records && records->which == Z_Records_NSD)
- {
- int http_code;
- http_code = z_to_srw_diag(odr_encode(), srw_res,
- records->u.nonSurrogateDiagnostic);
- if (http_code)
- return send_http_response(http_code);
- }
- return send_srw_response(srw_pdu);
-
-}
-
-int Yaz_Proxy::send_srw_explain_response(Z_SRW_diagnostic *diagnostics,
- int num_diagnostics)
-{
- Yaz_ProxyConfig *cfg = check_reconfigure();
- if (cfg)
- {
- int len;
- char *b = cfg->get_explain(odr_encode(), 0 /* target */,
- m_s2z_database, &len);
- if (b)
- {
- Z_SRW_PDU *res = yaz_srw_get(odr_encode(), Z_SRW_explain_response);
- Z_SRW_explainResponse *er = res->u.explain_response;
-
- er->record.recordData_buf = b;
- er->record.recordData_len = len;
- er->record.recordPacking = m_s2z_packing;
- er->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
-
- er->diagnostics = diagnostics;
- er->num_diagnostics = num_diagnostics;
- return send_srw_response(res);
- }
- }
- return send_http_response(404);
-}
-
-int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu)
-{
- if (m_http_version)
- {
- if (apdu->which == Z_APDU_initResponse)
- {
- Z_InitResponse *res = apdu->u.initResponse;
- if (*res->result == 0)
- {
- send_to_srw_client_error(3, 0);
- }
- else if (!m_s2z_search_apdu)
- {
- send_srw_explain_response(0, 0);
- }
- else
- {
- handle_incoming_Z_PDU(m_s2z_search_apdu);
- }
- }
- else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse)
- {
- m_s2z_search_apdu = 0;
- Z_SearchResponse *res = apdu->u.searchResponse;
- m_s2z_hit_count = *res->resultCount;
- if (res->records && res->records->which == Z_Records_NSD)
- {
- send_to_srw_client_ok(0, res->records, 1);
- }
- else if (m_s2z_present_apdu && m_s2z_hit_count > 0)
- {
- // adjust
- Z_PresentRequest *pr = m_s2z_present_apdu->u.presentRequest;
-
- if (*pr->resultSetStartPoint <= m_s2z_hit_count)
- {
- if (*pr->numberOfRecordsRequested+ *pr->resultSetStartPoint
- > m_s2z_hit_count)
- *pr->numberOfRecordsRequested =
- 1 + m_s2z_hit_count - *pr->resultSetStartPoint;
- }
- handle_incoming_Z_PDU(m_s2z_present_apdu);
- }
- else
- {
- m_s2z_present_apdu = 0;
- send_to_srw_client_ok(m_s2z_hit_count, res->records, 1);
- }
- }
- else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse)
- {
- int start =
- *m_s2z_present_apdu->u.presentRequest->resultSetStartPoint;
-
- m_s2z_present_apdu = 0;
- Z_PresentResponse *res = apdu->u.presentResponse;
- send_to_srw_client_ok(m_s2z_hit_count, res->records, start);
- }
- }
- else
- {
- int len = 0;
- if (m_log_mask & PROXY_LOG_REQ_CLIENT)
- yaz_log (LOG_LOG, "%sSending %s to client", m_session_str,
- apdu_name(apdu));
- int r = send_Z_PDU(apdu, &len);
- m_bytes_sent += len;
- m_bw_stat.add_bytes(len);
- logtime();
- return r;
- }
- return 0;
-}
-
-int Yaz_Proxy::send_to_client(Z_APDU *apdu)
-{
- int kill_session = 0;
- Z_ReferenceId **new_id = get_referenceIdP(apdu);
-
- if (new_id)
- *new_id = m_referenceId;
-
- if (apdu->which == Z_APDU_searchResponse)
- {
- Z_SearchResponse *sr = apdu->u.searchResponse;
- Z_Records *p = sr->records;
- if (p && p->which == Z_Records_NSD)
- {
- Z_DiagRec dr, *dr_p = &dr;
- dr.which = Z_DiagRec_defaultFormat;
- dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
-
- *sr->searchStatus = 0;
- display_diagrecs(&dr_p, 1);
- }
- else
- {
- if (p && p->which == Z_Records_DBOSD)
- {
- if (m_marcxml_flag)
- convert_to_marcxml(p->u.databaseOrSurDiagnostics);
- if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
- return 0;
-
- }
- if (sr->resultCount)
- {
- yaz_log(LOG_LOG, "%s%d hits", m_session_str,
- *sr->resultCount);
- if (*sr->resultCount < 0)
- {
- m_invalid_session = 1;
- kill_session = 1;
-
- *sr->searchStatus = 0;
- sr->records =
- create_nonSurrogateDiagnostics(odr_encode(), 2, 0);
- *sr->resultCount = 0;
- }
- }
- }
- }
- else if (apdu->which == Z_APDU_presentResponse)
- {
- Z_PresentResponse *sr = apdu->u.presentResponse;
- Z_Records *p = sr->records;
- if (p && p->which == Z_Records_NSD)
- {
- Z_DiagRec dr, *dr_p = &dr;
- dr.which = Z_DiagRec_defaultFormat;
- dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
- if (*sr->presentStatus == Z_PresentStatus_success)
- *sr->presentStatus = Z_PresentStatus_failure;
- display_diagrecs(&dr_p, 1);
- }
- if (p && p->which == Z_Records_DBOSD)
- {
- if (m_marcxml_flag)
- convert_to_marcxml(p->u.databaseOrSurDiagnostics);
- if (convert_xsl(p->u.databaseOrSurDiagnostics, apdu))
- return 0;
- }
- }
- else if (apdu->which == Z_APDU_initResponse)
- {
- if (m_initRequest_options)
- {
- Z_Options *nopt =
- (Odr_bitmask *)odr_malloc(odr_encode(),
- sizeof(Odr_bitmask));
- ODR_MASK_ZERO(nopt);
-
- int i;
- for (i = 0; i<24; i++)
- if (ODR_MASK_GET(m_initRequest_options, i) &&
- ODR_MASK_GET(apdu->u.initResponse->options, i))
- ODR_MASK_SET(nopt, i);
- apdu->u.initResponse->options = nopt;
- }
- if (m_initRequest_version)
- {
- Z_ProtocolVersion *nopt =
- (Odr_bitmask *)odr_malloc(odr_encode(),
- sizeof(Odr_bitmask));
- ODR_MASK_ZERO(nopt);
-
- int i;
- for (i = 0; i<8; i++)
- if (ODR_MASK_GET(m_initRequest_version, i) &&
- ODR_MASK_GET(apdu->u.initResponse->protocolVersion, i))
- ODR_MASK_SET(nopt, i);
- apdu->u.initResponse->protocolVersion = nopt;
- }
- apdu->u.initResponse->preferredMessageSize =
- odr_intdup(odr_encode(),
- m_client->m_initResponse_preferredMessageSize >
- m_initRequest_preferredMessageSize ?
- m_initRequest_preferredMessageSize :
- m_client->m_initResponse_preferredMessageSize);
- apdu->u.initResponse->maximumRecordSize =
- odr_intdup(odr_encode(),
- m_client->m_initResponse_maximumRecordSize >
- m_initRequest_maximumRecordSize ?
- m_initRequest_maximumRecordSize :
- m_client->m_initResponse_maximumRecordSize);
- }
- int r = send_PDU_convert(apdu);
- if (r)
- return r;
- if (kill_session)
- {
- delete m_client;
- m_client = 0;
- m_parent->pre_init();
- }
- return r;
-}
-
-int Yaz_ProxyClient::send_to_target(Z_APDU *apdu)
-{
- int len = 0;
- const char *apdu_name_tmp = apdu_name(apdu);
- int r = send_Z_PDU(apdu, &len);
- if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
- yaz_log (LOG_LOG, "%sSending %s to %s %d bytes",
- get_session_str(),
- apdu_name_tmp, get_hostname(), len);
- m_bytes_sent += len;
- return r;
-}
-
-Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu)
-{
- if (apdu->which == Z_APDU_presentRequest)
- {
- Z_PresentRequest *pr = apdu->u.presentRequest;
- int toget = *pr->numberOfRecordsRequested;
- int start = *pr->resultSetStartPoint;
-
- yaz_log(LOG_LOG, "%sPresent %s %d+%d", m_session_str,
- pr->resultSetId, start, toget);
-
- if (*m_parent->m_optimize == '0')
- return apdu;
-
- if (!m_client->m_last_resultSetId)
- {
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
- new_apdu->u.presentResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(), 30,
- pr->resultSetId);
- send_to_client(new_apdu);
- return 0;
- }
- if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId))
- {
- if (start+toget-1 > m_client->m_last_resultCount)
- {
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
- new_apdu->u.presentResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(), 13, 0);
- send_to_client(new_apdu);
- return 0;
- }
- Z_NamePlusRecordList *npr;
- if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget,
- pr->preferredRecordSyntax,
- pr->recordComposition))
- {
- yaz_log (LOG_LOG, "%sReturned cached records for present request",
- m_session_str);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
- new_apdu->u.presentResponse->referenceId = pr->referenceId;
-
- new_apdu->u.presentResponse->numberOfRecordsReturned
- = odr_intdup(odr_encode(), toget);
-
- new_apdu->u.presentResponse->records = (Z_Records*)
- odr_malloc(odr_encode(), sizeof(Z_Records));
- new_apdu->u.presentResponse->records->which = Z_Records_DBOSD;
- new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr;
- new_apdu->u.presentResponse->nextResultSetPosition =
- odr_intdup(odr_encode(), start+toget);
-
- send_to_client(new_apdu);
- return 0;
- }
- }
- }
-
- if (apdu->which != Z_APDU_searchRequest)
- return apdu;
- Z_SearchRequest *sr = apdu->u.searchRequest;
- Yaz_Z_Query *this_query = new Yaz_Z_Query;
- Yaz_Z_Databases this_databases;
-
- this_databases.set(sr->num_databaseNames, (const char **)
- sr->databaseNames);
-
- this_query->set_Z_Query(sr->query);
-
- char query_str[120];
- this_query->print(query_str, sizeof(query_str)-1);
- yaz_log(LOG_LOG, "%sSearch %s", m_session_str, query_str);
-
- if (*m_parent->m_optimize != '0' &&
- m_client->m_last_ok && m_client->m_last_query &&
- m_client->m_last_query->match(this_query) &&
- !strcmp(m_client->m_last_resultSetId, sr->resultSetName) &&
- m_client->m_last_databases.match(this_databases))
- {
- delete this_query;
- if (m_client->m_last_resultCount > *sr->smallSetUpperBound &&
- m_client->m_last_resultCount < *sr->largeSetLowerBound)
- {
- Z_NamePlusRecordList *npr;
- int toget = *sr->mediumSetPresentNumber;
- Z_RecordComposition *comp = 0;
-
- if (toget > m_client->m_last_resultCount)
- toget = m_client->m_last_resultCount;
-
- if (sr->mediumSetElementSetNames)
- {
- comp = (Z_RecordComposition *)
- odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
- comp->which = Z_RecordComp_simple;
- comp->u.simple = sr->mediumSetElementSetNames;
- }
-
- if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
- sr->preferredRecordSyntax, comp))
- {
- yaz_log (LOG_LOG, "%sReturned cached records for medium set",
- m_session_str);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->resultCount =
- &m_client->m_last_resultCount;
-
- new_apdu->u.searchResponse->numberOfRecordsReturned
- = odr_intdup(odr_encode(), toget);
-
- new_apdu->u.searchResponse->presentStatus =
- odr_intdup(odr_encode(), Z_PresentStatus_success);
- new_apdu->u.searchResponse->records = (Z_Records*)
- odr_malloc(odr_encode(), sizeof(Z_Records));
- new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
- new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
- new_apdu->u.searchResponse->nextResultSetPosition =
- odr_intdup(odr_encode(), toget+1);
- send_to_client(new_apdu);
- return 0;
- }
- else
- {
- // medium Set
- // send present request (medium size)
- yaz_log (LOG_LOG, "%sOptimizing search for medium set",
- m_session_str);
-
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
- Z_PresentRequest *pr = new_apdu->u.presentRequest;
- pr->referenceId = sr->referenceId;
- pr->resultSetId = sr->resultSetName;
- pr->preferredRecordSyntax = sr->preferredRecordSyntax;
- *pr->numberOfRecordsRequested = toget;
- pr->recordComposition = comp;
- m_client->m_sr_transform = 1;
- return new_apdu;
- }
- }
- else if (m_client->m_last_resultCount >= *sr->largeSetLowerBound ||
- m_client->m_last_resultCount <= 0)
- {
- // large set. Return pseudo-search response immediately
- yaz_log (LOG_LOG, "%sOptimizing search for large set",
- m_session_str);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->resultCount =
- &m_client->m_last_resultCount;
- send_to_client(new_apdu);
- return 0;
- }
- else
- {
- Z_NamePlusRecordList *npr;
- int toget = m_client->m_last_resultCount;
- Z_RecordComposition *comp = 0;
- // small set
- // send a present request (small set)
-
- if (sr->smallSetElementSetNames)
- {
- comp = (Z_RecordComposition *)
- odr_malloc(odr_encode(), sizeof(Z_RecordComposition));
- comp->which = Z_RecordComp_simple;
- comp->u.simple = sr->smallSetElementSetNames;
- }
-
- if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget,
- sr->preferredRecordSyntax, comp))
- {
- yaz_log (LOG_LOG, "%sReturned cached records for small set",
- m_session_str);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->resultCount =
- &m_client->m_last_resultCount;
-
- new_apdu->u.searchResponse->numberOfRecordsReturned
- = odr_intdup(odr_encode(), toget);
-
- new_apdu->u.searchResponse->presentStatus =
- odr_intdup(odr_encode(), Z_PresentStatus_success);
- new_apdu->u.searchResponse->records = (Z_Records*)
- odr_malloc(odr_encode(), sizeof(Z_Records));
- new_apdu->u.searchResponse->records->which = Z_Records_DBOSD;
- new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr;
- new_apdu->u.searchResponse->nextResultSetPosition =
- odr_intdup(odr_encode(), toget+1);
- send_to_client(new_apdu);
- return 0;
- }
- else
- {
- yaz_log (LOG_LOG, "%sOptimizing search for small set",
- m_session_str);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest);
- Z_PresentRequest *pr = new_apdu->u.presentRequest;
- pr->referenceId = sr->referenceId;
- pr->resultSetId = sr->resultSetName;
- pr->preferredRecordSyntax = sr->preferredRecordSyntax;
- *pr->numberOfRecordsRequested = toget;
- pr->recordComposition = comp;
- m_client->m_sr_transform = 1;
- return new_apdu;
- }
- }
- }
- else // query doesn't match
- {
- delete m_client->m_last_query;
- m_client->m_last_query = this_query;
- m_client->m_last_ok = 0;
- m_client->m_cache.clear();
- m_client->m_resultSetStartPoint = 0;
-
- xfree (m_client->m_last_resultSetId);
- m_client->m_last_resultSetId = xstrdup (sr->resultSetName);
-
- m_client->m_last_databases.set(sr->num_databaseNames,
- (const char **) sr->databaseNames);
- }
- return apdu;
-}
-
-
-void Yaz_Proxy::inc_request_no()
-{
- char *cp = strchr(m_session_str, ' ');
- m_request_no++;
- if (cp)
- sprintf(cp+1, "%d ", m_request_no);
-}
-
-void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len)
-{
- inc_request_no();
-
- m_bytes_recv += len;
-
- if (m_log_mask & PROXY_LOG_REQ_CLIENT)
- yaz_log (LOG_LOG, "%sReceiving %s from client %d bytes",
- m_session_str, gdu_name(apdu), len);
-
- if (m_bw_hold_PDU) // double incoming PDU. shutdown now.
- shutdown();
-
- m_bw_stat.add_bytes(len);
- m_pdu_stat.add_bytes(1);
-
- gettimeofday(&m_time_tv, 0);
-
- int bw_total = m_bw_stat.get_total();
- int pdu_total = m_pdu_stat.get_total();
-
- int reduce = 0;
- if (m_bw_max)
- {
- if (bw_total > m_bw_max)
- {
- reduce = (bw_total/m_bw_max);
- }
- }
- if (m_pdu_max)
- {
- if (pdu_total > m_pdu_max)
- {
- int nreduce = (m_pdu_max >= 60) ? 1 : 60/m_pdu_max;
- reduce = (reduce > nreduce) ? reduce : nreduce;
- }
- }
- if (reduce)
- {
- yaz_log(LOG_LOG, "%sdelay=%d bw=%d pdu=%d limit-bw=%d limit-pdu=%d",
- m_session_str, reduce, bw_total, pdu_total,
- m_bw_max, m_pdu_max);
-
- m_bw_hold_PDU = apdu; // save PDU and signal "on hold"
- timeout(reduce); // call us reduce seconds later
- }
- else if (apdu->which == Z_GDU_Z3950)
- handle_incoming_Z_PDU(apdu->u.z3950);
- else if (apdu->which == Z_GDU_HTTP_Request)
- handle_incoming_HTTP(apdu->u.HTTP_Request);
-}
-
-void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu)
-{
- if (m_max_record_retrieve)
- {
- if (apdu->which == Z_APDU_presentRequest)
- {
- Z_PresentRequest *pr = apdu->u.presentRequest;
- if (pr->numberOfRecordsRequested &&
- *pr->numberOfRecordsRequested > m_max_record_retrieve)
- *pr->numberOfRecordsRequested = m_max_record_retrieve;
- }
- }
-}
-
-Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr,
- int error,
- const char *addinfo)
-{
- Z_Records *rec = (Z_Records *)
- odr_malloc (odr, sizeof(*rec));
- int *err = (int *)
- odr_malloc (odr, sizeof(*err));
- Z_DiagRec *drec = (Z_DiagRec *)
- odr_malloc (odr, sizeof(*drec));
- Z_DefaultDiagFormat *dr = (Z_DefaultDiagFormat *)
- odr_malloc (odr, sizeof(*dr));
- *err = error;
- rec->which = Z_Records_NSD;
- rec->u.nonSurrogateDiagnostic = dr;
- dr->diagnosticSetId =
- yaz_oidval_to_z3950oid (odr, CLASS_DIAGSET, VAL_BIB1);
- dr->condition = err;
- dr->which = Z_DefaultDiagFormat_v2Addinfo;
- dr->u.v2Addinfo = odr_strdup (odr, addinfo ? addinfo : "");
- return rec;
-}
-
-Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu)
-{
- if (apdu->which == Z_APDU_searchRequest &&
- apdu->u.searchRequest->query &&
- apdu->u.searchRequest->query->which == Z_Query_type_104 &&
- apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL)
- {
- Z_RPNQuery *rpnquery = 0;
- Z_SearchRequest *sr = apdu->u.searchRequest;
- char *addinfo = 0;
-
- yaz_log(LOG_LOG, "%sCQL: %s", m_session_str,
- sr->query->u.type_104->u.cql);
-
- int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql,
- &rpnquery, odr_encode(),
- &addinfo);
- if (r == -3)
- yaz_log(LOG_LOG, "%sNo CQL to RPN table", m_session_str);
- else if (r)
- {
- yaz_log(LOG_LOG, "%sCQL Conversion error %d", m_session_str, r);
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
-
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(),
- yaz_diag_srw_to_bib1(r),
- addinfo);
- *new_apdu->u.searchResponse->searchStatus = 0;
-
- send_to_client(new_apdu);
-
- return 0;
- }
- else
- {
- sr->query->which = Z_Query_type_1;
- sr->query->u.type_1 = rpnquery;
- }
- return apdu;
- }
- return apdu;
-}
-
-Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu)
-{
- if (apdu->which == Z_APDU_searchRequest)
- {
- Z_SearchRequest *sr = apdu->u.searchRequest;
- int err = 0;
- char *addinfo = 0;
-
- Yaz_ProxyConfig *cfg = check_reconfigure();
- if (cfg)
- err = cfg->check_query(odr_encode(), m_default_target,
- sr->query, &addinfo);
- if (err)
- {
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
-
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
- *new_apdu->u.searchResponse->searchStatus = 0;
-
- send_to_client(new_apdu);
-
- return 0;
- }
- }
- return apdu;
-}
-
-Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu)
-{
- m_marcxml_flag = 0;
- if (apdu->which == Z_APDU_searchRequest)
- {
- Z_SearchRequest *sr = apdu->u.searchRequest;
- int err = 0;
- char *addinfo = 0;
- Yaz_ProxyConfig *cfg = check_reconfigure();
-
- Z_RecordComposition rc_temp, *rc = 0;
- if (sr->smallSetElementSetNames)
- {
- rc_temp.which = Z_RecordComp_simple;
- rc_temp.u.simple = sr->smallSetElementSetNames;
- rc = &rc_temp;
- }
-
- char *stylesheet_name = 0;
- if (cfg)
- err = cfg->check_syntax(odr_encode(),
- m_default_target,
- sr->preferredRecordSyntax, rc,
- &addinfo, &stylesheet_name, &m_schema);
- if (stylesheet_name)
- {
- m_parent->low_socket_close();
-
- if (m_stylesheet_xsp)
- xsltFreeStylesheet(m_stylesheet_xsp);
-
- m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
- stylesheet_name);
- m_stylesheet_offset = 0;
- xfree(stylesheet_name);
-
- m_parent->low_socket_open();
- }
- if (err == -1)
- {
- sr->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(odr_encode(), CLASS_RECSYN, VAL_USMARC);
- m_marcxml_flag = 1;
- }
- else if (err)
- {
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
-
- new_apdu->u.searchResponse->referenceId = sr->referenceId;
- new_apdu->u.searchResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
- *new_apdu->u.searchResponse->searchStatus = 0;
-
- send_to_client(new_apdu);
-
- return 0;
- }
- }
- else if (apdu->which == Z_APDU_presentRequest)
- {
- Z_PresentRequest *pr = apdu->u.presentRequest;
- int err = 0;
- char *addinfo = 0;
- Yaz_ProxyConfig *cfg = check_reconfigure();
-
- char *stylesheet_name = 0;
- if (cfg)
- err = cfg->check_syntax(odr_encode(), m_default_target,
- pr->preferredRecordSyntax,
- pr->recordComposition,
- &addinfo, &stylesheet_name, &m_schema);
- if (stylesheet_name)
- {
- m_parent->low_socket_close();
-
- if (m_stylesheet_xsp)
- xsltFreeStylesheet(m_stylesheet_xsp);
-
- m_stylesheet_xsp = xsltParseStylesheetFile((const xmlChar*)
- stylesheet_name);
- m_stylesheet_offset = 0;
- xfree(stylesheet_name);
-
- m_parent->low_socket_open();
- }
- if (err == -1)
- {
- pr->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(odr_decode(), CLASS_RECSYN, VAL_USMARC);
- m_marcxml_flag = 1;
- }
- else if (err)
- {
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse);
-
- new_apdu->u.presentResponse->referenceId = pr->referenceId;
- new_apdu->u.presentResponse->records =
- create_nonSurrogateDiagnostics(odr_encode(), err, addinfo);
- *new_apdu->u.presentResponse->presentStatus =
- Z_PresentStatus_failure;
-
- send_to_client(new_apdu);
-
- return 0;
- }
- }
- return apdu;
-}
-
-Z_ElementSetNames *Yaz_Proxy::mk_esn_from_schema(ODR o, const char *schema)
-{
- if (!schema)
- return 0;
- Z_ElementSetNames *esn = (Z_ElementSetNames *)
- odr_malloc(o, sizeof(Z_ElementSetNames));
- esn->which = Z_ElementSetNames_generic;
- esn->u.generic = odr_strdup(o, schema);
- return esn;
-}
-
-void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq)
-{
- if (m_s2z_odr_init)
- {
- odr_destroy(m_s2z_odr_init);
- m_s2z_odr_init = 0;
- }
- if (m_s2z_odr_search)
- {
- odr_destroy(m_s2z_odr_search);
- m_s2z_odr_search = 0;
- }
-
- m_http_keepalive = 0;
- m_http_version = 0;
- if (!strcmp(hreq->version, "1.0"))
- {
- const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
- if (v && !strcmp(v, "Keep-Alive"))
- m_http_keepalive = 1;
- else
- m_http_keepalive = 0;
- m_http_version = "1.0";
- }
- else
- {
- const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
- if (v && !strcmp(v, "close"))
- m_http_keepalive = 0;
- else
- m_http_keepalive = 1;
- m_http_version = "1.1";
- }
-
- Z_SRW_PDU *srw_pdu = 0;
- Z_SOAP *soap_package = 0;
- char *charset = 0;
- Z_SRW_diagnostic *diagnostic = 0;
- int num_diagnostic = 0;
- if (yaz_srw_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
- &charset) == 0
- || yaz_sru_decode(hreq, &srw_pdu, &soap_package, odr_decode(),
- &charset, &diagnostic, &num_diagnostic) == 0)
- {
- m_s2z_odr_init = odr_createmem(ODR_ENCODE);
- m_s2z_odr_search = odr_createmem(ODR_ENCODE);
- m_soap_ns = odr_strdup(m_s2z_odr_search, soap_package->ns);
- m_s2z_init_apdu = 0;
- m_s2z_search_apdu = 0;
- m_s2z_present_apdu = 0;
-
- m_s2z_stylesheet = 0;
-
- if (srw_pdu->which == Z_SRW_searchRetrieve_request)
- {
- Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request;
-
- m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
- // recordXPath unsupported.
- if (srw_req->recordXPath)
- {
- yaz_add_srw_diagnostic(odr_decode(),
- &diagnostic, &num_diagnostic,
- 72, 0);
- }
- // must have a query
- if (!srw_req->query.cql)
- {
- yaz_add_srw_diagnostic(odr_decode(),
- &diagnostic, &num_diagnostic,
- 7, "query");
- }
- // sort unsupported
- if (srw_req->sort_type != Z_SRW_sort_type_none)
- {
- yaz_add_srw_diagnostic(odr_decode(),
- &diagnostic, &num_diagnostic,
- 80, 0);
- }
- // save stylesheet
- if (srw_req->stylesheet)
- m_s2z_stylesheet =
- odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
-
- // set packing for response records ..
- if (srw_req->recordPacking &&
- !strcmp(srw_req->recordPacking, "xml"))
- m_s2z_packing = Z_SRW_recordPacking_XML;
- else
- m_s2z_packing = Z_SRW_recordPacking_string;
-
- if (num_diagnostic)
- {
- Z_SRW_PDU *srw_pdu =
- yaz_srw_get(odr_encode(),
- Z_SRW_searchRetrieve_response);
- Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response;
-
- srw_res->diagnostics = diagnostic;
- srw_res->num_diagnostics = num_diagnostic;
- send_srw_response(srw_pdu);
- return;
- }
-
- // prepare search PDU
- m_s2z_search_apdu = zget_APDU(m_s2z_odr_search,
- Z_APDU_searchRequest);
- Z_SearchRequest *z_searchRequest =
- m_s2z_search_apdu->u.searchRequest;
-
- z_searchRequest->num_databaseNames = 1;
- z_searchRequest->databaseNames = (char**)
- odr_malloc(m_s2z_odr_search, sizeof(char *));
- z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
- srw_req->database);
-
- // query transformation
- Z_Query *query = (Z_Query *)
- odr_malloc(m_s2z_odr_search, sizeof(Z_Query));
- z_searchRequest->query = query;
-
- if (srw_req->query_type == Z_SRW_query_type_cql)
- {
- Z_External *ext = (Z_External *)
- odr_malloc(m_s2z_odr_search, sizeof(*ext));
- ext->direct_reference =
- odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
- ext->indirect_reference = 0;
- ext->descriptor = 0;
- ext->which = Z_External_CQL;
- ext->u.cql = srw_req->query.cql;
-
- query->which = Z_Query_type_104;
- query->u.type_104 = ext;
- }
- else if (srw_req->query_type == Z_SRW_query_type_pqf)
- {
- Z_RPNQuery *RPNquery;
- YAZ_PQF_Parser pqf_parser;
-
- pqf_parser = yaz_pqf_create ();
-
- RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
- srw_req->query.pqf);
- if (!RPNquery)
- {
- const char *pqf_msg;
- size_t off;
- int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
- yaz_log(LOG_LOG, "%*s^\n", off+4, "");
- yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
-
- send_to_srw_client_error(10, 0);
- return;
- }
- query->which = Z_Query_type_1;
- query->u.type_1 = RPNquery;
-
- yaz_pqf_destroy (pqf_parser);
- }
- else
- {
- send_to_srw_client_error(7, "query");
- return;
- }
-
- // present
- m_s2z_present_apdu = 0;
- int max = 0;
- if (srw_req->maximumRecords)
- max = *srw_req->maximumRecords;
- int start = 1;
- if (srw_req->startRecord)
- start = *srw_req->startRecord;
- if (max > 0)
- {
- // Some backend, such as Voyager doesn't honor piggyback
- // So we use present always (0 &&).
- if (0 && start <= 1) // Z39.50 piggyback
- {
- *z_searchRequest->smallSetUpperBound = max;
- *z_searchRequest->mediumSetPresentNumber = max;
- *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9
-
- z_searchRequest->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
- VAL_TEXT_XML);
- if (srw_req->recordSchema)
- {
- z_searchRequest->smallSetElementSetNames =
- z_searchRequest->mediumSetElementSetNames =
- mk_esn_from_schema(m_s2z_odr_search,
- srw_req->recordSchema);
- }
- }
- else // Z39.50 present
- {
- m_s2z_present_apdu = zget_APDU(m_s2z_odr_search,
- Z_APDU_presentRequest);
- Z_PresentRequest *z_presentRequest =
- m_s2z_present_apdu->u.presentRequest;
- *z_presentRequest->resultSetStartPoint = start;
- *z_presentRequest->numberOfRecordsRequested = max;
- z_presentRequest->preferredRecordSyntax =
- yaz_oidval_to_z3950oid(m_s2z_odr_search, CLASS_RECSYN,
- VAL_TEXT_XML);
- if (srw_req->recordSchema)
- {
- z_presentRequest->recordComposition =
- (Z_RecordComposition *)
- odr_malloc(m_s2z_odr_search,
- sizeof(Z_RecordComposition));
- z_presentRequest->recordComposition->which =
- Z_RecordComp_simple;
- z_presentRequest->recordComposition->u.simple =
- mk_esn_from_schema(m_s2z_odr_search,
- srw_req->recordSchema);
- }
- }
- }
- if (!m_client)
- {
- m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
- Z_APDU_initRequest);
-
- // prevent m_initRequest_apdu memory from being grabbed
- // in Yaz_Proxy::handle_incoming_Z_PDU
- m_initRequest_apdu = m_s2z_init_apdu;
- handle_incoming_Z_PDU(m_s2z_init_apdu);
- return;
- }
- else
- {
- handle_incoming_Z_PDU(m_s2z_search_apdu);
- return;
- }
- }
- else if (srw_pdu->which == Z_SRW_explain_request)
- {
- Z_SRW_explainRequest *srw_req = srw_pdu->u.explain_request;
-
- m_s2z_database = odr_strdup(m_s2z_odr_init, srw_req->database);
-
- // save stylesheet
- if (srw_req->stylesheet)
- m_s2z_stylesheet =
- odr_strdup(m_s2z_odr_init, srw_req->stylesheet);
-
- if (srw_req->recordPacking &&
- !strcmp(srw_req->recordPacking, "xml"))
- m_s2z_packing = Z_SRW_recordPacking_XML;
- else
- m_s2z_packing = Z_SRW_recordPacking_string;
-
- if (num_diagnostic)
- {
- send_srw_explain_response(diagnostic, num_diagnostic);
- return;
- }
-
- if (!m_client)
- {
- m_s2z_init_apdu = zget_APDU(m_s2z_odr_init,
- Z_APDU_initRequest);
-
- // prevent m_initRequest_apdu memory from being grabbed
- // in Yaz_Proxy::handle_incoming_Z_PDU
- m_initRequest_apdu = m_s2z_init_apdu;
- handle_incoming_Z_PDU(m_s2z_init_apdu);
- }
- else
- send_srw_explain_response(0, 0);
- return;
- }
- else if (srw_pdu->which == Z_SRW_scan_request)
- {
- m_s2z_database = odr_strdup(m_s2z_odr_init,
- srw_pdu->u.scan_request->database);
-
- yaz_add_srw_diagnostic(odr_decode(),
- &diagnostic, &num_diagnostic,
- 4, "scan");
- Z_SRW_PDU *srw_pdu =
- yaz_srw_get(odr_encode(),
- Z_SRW_scan_response);
- Z_SRW_scanResponse *srw_res = srw_pdu->u.scan_response;
-
- srw_res->diagnostics = diagnostic;
- srw_res->num_diagnostics = num_diagnostic;
- send_srw_response(srw_pdu);
- return;
- }
- else
- {
- m_s2z_database = 0;
-
- send_to_srw_client_error(4, 0);
- }
- }
- int len = 0;
- Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400);
- timeout(0);
- send_GDU(p, &len);
-}
-
-void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu)
-{
- Z_ReferenceId **refid = get_referenceIdP(apdu);
- nmem_reset(m_referenceId_mem);
- if (refid && *refid)
- {
- m_referenceId = (Z_ReferenceId *)
- nmem_malloc(m_referenceId_mem, sizeof(*m_referenceId));
- m_referenceId->len = m_referenceId->size = (*refid)->len;
- m_referenceId->buf = (unsigned char *)
- nmem_malloc(m_referenceId_mem, (*refid)->len);
- memcpy(m_referenceId->buf, (*refid)->buf, (*refid)->len);
- }
- else
- m_referenceId = 0;
-
- if (!m_client && m_invalid_session)
- {
- m_apdu_invalid_session = apdu;
- m_mem_invalid_session = odr_extract_mem(odr_decode());
- apdu = m_initRequest_apdu;
- }
-
- // Determine our client.
- Z_OtherInformation **oi;
- get_otherInfoAPDU(apdu, &oi);
- m_client = get_client(apdu, get_cookie(oi), get_proxy(oi));
- if (!m_client)
- {
- delete this;
- return;
- }
- m_client->m_server = this;
-
- if (apdu->which == Z_APDU_initRequest)
- {
- if (apdu->u.initRequest->implementationId)
- yaz_log(LOG_LOG, "%simplementationId: %s",
- m_session_str, apdu->u.initRequest->implementationId);
- if (apdu->u.initRequest->implementationName)
- yaz_log(LOG_LOG, "%simplementationName: %s",
- m_session_str, apdu->u.initRequest->implementationName);
- if (apdu->u.initRequest->implementationVersion)
- yaz_log(LOG_LOG, "%simplementationVersion: %s",
- m_session_str, apdu->u.initRequest->implementationVersion);
- if (m_initRequest_apdu == 0)
- {
- if (m_initRequest_mem)
- nmem_destroy(m_initRequest_mem);
- m_initRequest_apdu = apdu;
- m_initRequest_mem = odr_extract_mem(odr_decode());
-
- m_initRequest_preferredMessageSize = *apdu->u.initRequest->
- preferredMessageSize;
- *apdu->u.initRequest->preferredMessageSize = 1024*1024;
- m_initRequest_maximumRecordSize = *apdu->u.initRequest->
- maximumRecordSize;
- *apdu->u.initRequest->maximumRecordSize = 1024*1024;
-
- // save init options for the response..
- m_initRequest_options = apdu->u.initRequest->options;
-
- apdu->u.initRequest->options =
- (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
- sizeof(Odr_bitmask));
- ODR_MASK_ZERO(apdu->u.initRequest->options);
- int i;
- for (i = 0; i<= 24; i++)
- ODR_MASK_SET(apdu->u.initRequest->options, i);
- ODR_MASK_CLEAR(apdu->u.initRequest->options,
- Z_Options_negotiationModel);
- ODR_MASK_CLEAR(apdu->u.initRequest->options,
- Z_Options_concurrentOperations);
-
- // make new version
- m_initRequest_version = apdu->u.initRequest->protocolVersion;
- apdu->u.initRequest->protocolVersion =
- (Odr_bitmask *)nmem_malloc(m_initRequest_mem,
- sizeof(Odr_bitmask));
- ODR_MASK_ZERO(apdu->u.initRequest->protocolVersion);
-
- for (i = 0; i<= 8; i++)
- ODR_MASK_SET(apdu->u.initRequest->protocolVersion, i);
- }
- if (m_client->m_init_flag)
- {
- if (handle_init_response_for_invalid_session(apdu))
- return;
- if (m_client->m_initResponse)
- {
- Z_APDU *apdu2 = m_client->m_initResponse;
- apdu2->u.initResponse->otherInfo = 0;
- if (m_client->m_cookie && *m_client->m_cookie)
- set_otherInformationString(apdu2, VAL_COOKIE, 1,
- m_client->m_cookie);
- apdu2->u.initResponse->referenceId =
- apdu->u.initRequest->referenceId;
- apdu2->u.initResponse->options = m_client->m_initResponse_options;
- apdu2->u.initResponse->protocolVersion =
- m_client->m_initResponse_version;
-
- send_to_client(apdu2);
- return;
- }
- }
- m_client->m_init_flag = 1;
- }
- handle_max_record_retrieve(apdu);
-
- if (apdu)
- apdu = handle_syntax_validation(apdu);
-
- if (apdu)
- apdu = handle_query_transformation(apdu);
-
- if (apdu)
- apdu = handle_query_validation(apdu);
-
- if (apdu)
- apdu = result_set_optimize(apdu);
- if (!apdu)
- {
- m_client->timeout(m_target_idletime); // mark it active even
- // though we didn't use it
- return;
- }
-
- // delete other info part from PDU before sending to target
- get_otherInfoAPDU(apdu, &oi);
- if (oi)
- *oi = 0;
-
- if (apdu->which == Z_APDU_presentRequest &&
- m_client->m_resultSetStartPoint == 0)
- {
- Z_PresentRequest *pr = apdu->u.presentRequest;
- m_client->m_resultSetStartPoint = *pr->resultSetStartPoint;
- m_client->m_cache.copy_presentRequest(apdu->u.presentRequest);
- } else {
- m_client->m_resultSetStartPoint = 0;
- }
- if (m_client->send_to_target(apdu) < 0)
- {
- delete m_client;
- m_client = 0;
- delete this;
- }
- else
- m_client->m_waiting = 1;
-}
-
-void Yaz_Proxy::connectNotify()
-{
-}
-
-void Yaz_Proxy::shutdown()
-{
- m_invalid_session = 0;
- // only keep if keep_alive flag is set...
- if (m_client &&
- m_client->m_pdu_recv < m_keepalive_limit_pdu &&
- m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw &&
- m_client->m_waiting == 0)
- {
- yaz_log(LOG_LOG, "%sShutdown (client to proxy) keepalive %s",
- m_session_str,
- m_client->get_hostname());
- yaz_log(LOG_LOG, "%sbw=%d pdu=%d limit-bw=%d limit-pdu=%d",
- m_session_str, m_client->m_pdu_recv,
- m_client->m_bytes_sent + m_client->m_bytes_recv,
- m_keepalive_limit_bw, m_keepalive_limit_pdu);
- assert (m_client->m_waiting != 2);
- // Tell client (if any) that no server connection is there..
- m_client->m_server = 0;
- m_invalid_session = 0;
- }
- else if (m_client)
- {
- yaz_log (LOG_LOG, "%sShutdown (client to proxy) close %s",
- m_session_str,
- m_client->get_hostname());
- assert (m_client->m_waiting != 2);
- delete m_client;
- }
- else if (!m_parent)
- {
- yaz_log (LOG_LOG, "%sshutdown (client to proxy) bad state",
- m_session_str);
- assert (m_parent);
- }
- else
- {
- yaz_log (LOG_LOG, "%sShutdown (client to proxy)",
- m_session_str);
- }
- if (m_parent)
- m_parent->pre_init();
- delete this;
-}
-
-const char *Yaz_ProxyClient::get_session_str()
-{
- if (!m_server)
- return "0 ";
- return m_server->get_session_str();
-}
-
-void Yaz_ProxyClient::shutdown()
-{
- yaz_log (LOG_LOG, "%sShutdown (proxy to target) %s", get_session_str(),
- get_hostname());
- delete m_server;
- delete this;
-}
-
-void Yaz_Proxy::failNotify()
-{
- inc_request_no();
- yaz_log (LOG_LOG, "%sConnection closed by client",
- get_session_str());
- shutdown();
-}
-
-void Yaz_ProxyClient::failNotify()
-{
- if (m_server)
- m_server->inc_request_no();
- yaz_log (LOG_LOG, "%sConnection closed by target %s",
- get_session_str(), get_hostname());
- shutdown();
-}
-
-void Yaz_ProxyClient::connectNotify()
-{
- const char *s = get_session_str();
- const char *h = get_hostname();
- yaz_log (LOG_LOG, "%sConnection accepted by %s timeout=%d", s, h,
- m_target_idletime);
- timeout(m_target_idletime);
- if (!m_server)
- pre_init_client();
-}
-
-IYaz_PDU_Observer *Yaz_ProxyClient::sessionNotify(IYaz_PDU_Observable
- *the_PDU_Observable, int fd)
-{
- return new Yaz_ProxyClient(the_PDU_Observable, 0);
-}
-
-Yaz_ProxyClient::~Yaz_ProxyClient()
-{
- if (m_prev)
- *m_prev = m_next;
- if (m_next)
- m_next->m_prev = m_prev;
- m_waiting = 2; // for debugging purposes only.
- odr_destroy(m_init_odr);
- delete m_last_query;
- xfree (m_last_resultSetId);
- xfree (m_cookie);
-}
-
-void Yaz_ProxyClient::pre_init_client()
-{
- Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
- Z_InitRequest *req = apdu->u.initRequest;
-
- int i;
- for (i = 0; i<= 24; i++)
- ODR_MASK_SET(req->options, i);
- ODR_MASK_CLEAR(apdu->u.initRequest->options,
- Z_Options_negotiationModel);
- ODR_MASK_CLEAR(apdu->u.initRequest->options,
- Z_Options_concurrentOperations);
- for (i = 0; i<= 10; i++)
- ODR_MASK_SET(req->protocolVersion, i);
-
- if (send_to_target(apdu) < 0)
- {
- delete this;
- }
- else
- {
- m_waiting = 1;
- m_init_flag = 1;
- }
-}
-
-void Yaz_Proxy::pre_init()
-{
- int i;
- const char *name = 0;
- const char *zurl_in_use[MAX_ZURL_PLEX];
- int limit_bw, limit_pdu, limit_req;
- int target_idletime, client_idletime;
- int max_clients;
- int keepalive_limit_bw, keepalive_limit_pdu;
- int pre_init;
- const char *cql2rpn = 0;
-
- Yaz_ProxyConfig *cfg = check_reconfigure();
-
- zurl_in_use[0] = 0;
-
- if (m_log_mask & PROXY_LOG_APDU_CLIENT)
- set_APDU_yazlog(1);
- else
- set_APDU_yazlog(0);
-
- for (i = 0; cfg && cfg->get_target_no(i, &name, zurl_in_use,
- &limit_bw, &limit_pdu, &limit_req,
- &target_idletime, &client_idletime,
- &max_clients,
- &keepalive_limit_bw,
- &keepalive_limit_pdu,
- &pre_init,
- &cql2rpn) ; i++)
- {
- if (pre_init)
- {
- int j;
- for (j = 0; zurl_in_use[j]; j++)
- {
- Yaz_ProxyClient *c;
- int spare = 0;
- int spare_waiting = 0;
- int in_use = 0;
- int other = 0;
- for (c = m_clientPool; c; c = c->m_next)
- {
- if (!strcmp(zurl_in_use[j], c->get_hostname()))
- {
- if (c->m_cookie == 0)
- {
- if (c->m_server == 0)
- if (c->m_waiting)
- spare_waiting++;
- else
- spare++;
- else
- in_use++;
- }
- else
- other++;
- }
- }
- yaz_log(LOG_LOG, "%spre-init %s %s use=%d other=%d spare=%d "
- "sparew=%d preinit=%d",m_session_str,
- name, zurl_in_use[j], in_use, other,
- spare, spare_waiting, pre_init);
- if (spare + spare_waiting < pre_init)
- {
- c = new Yaz_ProxyClient(m_PDU_Observable->clone(), this);
- c->m_next = m_clientPool;
- if (c->m_next)
- c->m_next->m_prev = &c->m_next;
- m_clientPool = c;
- c->m_prev = &m_clientPool;
-
- if (m_log_mask & PROXY_LOG_APDU_SERVER)
- c->set_APDU_yazlog(1);
- else
- c->set_APDU_yazlog(0);
-
- if (c->client(zurl_in_use[j]))
- {
- timeout(60);
- delete c;
- return;
- }
- c->timeout(30);
- c->m_waiting = 1;
- c->m_target_idletime = target_idletime;
- c->m_seqno = m_seqno++;
- }
- }
- }
- }
-}
-
-void Yaz_Proxy::timeoutNotify()
-{
- if (m_parent)
- {
- if (m_bw_hold_PDU)
- {
- timeout(m_client_idletime);
- Z_GDU *apdu = m_bw_hold_PDU;
- m_bw_hold_PDU = 0;
-
- if (apdu->which == Z_GDU_Z3950)
- handle_incoming_Z_PDU(apdu->u.z3950);
- else if (apdu->which == Z_GDU_HTTP_Request)
- handle_incoming_HTTP(apdu->u.HTTP_Request);
- }
- else if (m_stylesheet_nprl)
- convert_xsl_delay();
- else
- {
- inc_request_no();
-
- yaz_log (LOG_LOG, "%sTimeout (client to proxy)", m_session_str);
- shutdown();
- }
- }
- else
- {
- timeout(600);
- pre_init();
- }
-}
-
-void Yaz_Proxy::markInvalid()
-{
- m_client = 0;
- m_invalid_session = 1;
-}
-
-void Yaz_ProxyClient::timeoutNotify()
-{
- if (m_server)
- m_server->inc_request_no();
-
- yaz_log (LOG_LOG, "%sTimeout (proxy to target) %s", get_session_str(),
- get_hostname());
- m_waiting = 1;
- m_root->pre_init();
- if (m_server && m_init_flag)
- {
- // target timed out in a session that was properly initialized
- // server object stay alive but we mark it as invalid so it
- // gets initialized again
- m_server->markInvalid();
- m_server = 0;
- }
- shutdown();
-}
-
-Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable,
- Yaz_Proxy *parent) :
- Yaz_Z_Assoc (the_PDU_Observable)
-{
- m_cookie = 0;
- m_next = 0;
- m_prev = 0;
- m_init_flag = 0;
- m_last_query = 0;
- m_last_resultSetId = 0;
- m_last_resultCount = 0;
- m_last_ok = 0;
- m_sr_transform = 0;
- m_waiting = 0;
- m_init_odr = odr_createmem (ODR_DECODE);
- m_initResponse = 0;
- m_initResponse_options = 0;
- m_initResponse_version = 0;
- m_initResponse_preferredMessageSize = 0;
- m_initResponse_maximumRecordSize = 0;
- m_resultSetStartPoint = 0;
- m_bytes_sent = m_bytes_recv = 0;
- m_pdu_recv = 0;
- m_server = 0;
- m_seqno = 0;
- m_target_idletime = 600;
- m_root = parent;
-}
-
-const char *Yaz_Proxy::option(const char *name, const char *value)
-{
- if (!strcmp (name, "optimize")) {
- if (value) {
- xfree (m_optimize);
- m_optimize = xstrdup (value);
- }
- return m_optimize;
- }
- return 0;
-}
-
-void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len)
-{
-
-}
-
-void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len)
-{
- if (apdu->which == Z_GDU_Z3950)
- recv_Z_PDU(apdu->u.z3950, len);
- else if (apdu->which == Z_GDU_HTTP_Response)
- recv_HTTP_response(apdu->u.HTTP_Response, len);
- else
- shutdown();
-}
-
-int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu)
-{
- if (!m_invalid_session)
- return 0;
- m_invalid_session = 0;
- handle_incoming_Z_PDU(m_apdu_invalid_session);
- assert (m_mem_invalid_session);
- nmem_destroy(m_mem_invalid_session);
- m_mem_invalid_session = 0;
- return 1;
-}
-
-void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len)
-{
- m_bytes_recv += len;
-
- m_pdu_recv++;
- m_waiting = 0;
- if (m_root->get_log_mask() & PROXY_LOG_REQ_SERVER)
- yaz_log (LOG_LOG, "%sReceiving %s from %s %d bytes", get_session_str(),
- apdu_name(apdu), get_hostname(), len);
- if (apdu->which == Z_APDU_initResponse)
- {
- if (!m_server) // if this is a pre init session , check for more
- m_root->pre_init();
- NMEM nmem = odr_extract_mem (odr_decode());
- odr_reset (m_init_odr);
- nmem_transfer (m_init_odr->mem, nmem);
- m_initResponse = apdu;
- m_initResponse_options = apdu->u.initResponse->options;
- m_initResponse_version = apdu->u.initResponse->protocolVersion;
- m_initResponse_preferredMessageSize =
- *apdu->u.initResponse->preferredMessageSize;
- m_initResponse_maximumRecordSize =
- *apdu->u.initResponse->maximumRecordSize;
-
- Z_InitResponse *ir = apdu->u.initResponse;
- char *im0 = ir->implementationName;
-
- char *im1 = (char*)
- odr_malloc(m_init_odr, 20 + (im0 ? strlen(im0) : 0));
- *im1 = '\0';
- if (im0)
- {
- strcat(im1, im0);
- strcat(im1, " ");
- }
- strcat(im1, "(YAZ Proxy)");
- ir->implementationName = im1;
-
- nmem_destroy (nmem);
-
- if (m_server && m_server->handle_init_response_for_invalid_session(apdu))
- return;
- }
- if (apdu->which == Z_APDU_searchResponse)
- {
- Z_SearchResponse *sr = apdu->u.searchResponse;
- m_last_resultCount = *sr->resultCount;
- int status = *sr->searchStatus;
- if (status && (!sr->records || sr->records->which == Z_Records_DBOSD))
- {
- m_last_ok = 1;
-
- if (sr->records && sr->records->which == Z_Records_DBOSD)
- {
- m_cache.add(odr_decode(),
- sr->records->u.databaseOrSurDiagnostics, 1,
- *sr->resultCount);
- }
- }
- }
- if (apdu->which == Z_APDU_presentResponse)
- {
- Z_PresentResponse *pr = apdu->u.presentResponse;
- if (m_sr_transform)
- {
- m_sr_transform = 0;
- Z_APDU *new_apdu = create_Z_PDU(Z_APDU_searchResponse);
- Z_SearchResponse *sr = new_apdu->u.searchResponse;
- sr->referenceId = pr->referenceId;
- *sr->resultCount = m_last_resultCount;
- sr->records = pr->records;
- sr->nextResultSetPosition = pr->nextResultSetPosition;
- sr->numberOfRecordsReturned = pr->numberOfRecordsReturned;
- apdu = new_apdu;
- }
- if (pr->records &&
- pr->records->which == Z_Records_DBOSD && m_resultSetStartPoint)
- {
- m_cache.add(odr_decode(),
- pr->records->u.databaseOrSurDiagnostics,
- m_resultSetStartPoint, -1);
- m_resultSetStartPoint = 0;
- }
- }
- if (m_cookie)
- set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
- if (m_server)
- {
- m_server->send_to_client(apdu);
- }
- if (apdu->which == Z_APDU_close)
- {
- shutdown();
- }
-}
-
-void Yaz_Proxy::low_socket_close()
-{
- int i;
- for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
- if (m_lo_fd[i] >= 0)
- ::close(m_lo_fd[i]);
-}
-
-void Yaz_Proxy::low_socket_open()
-{
- int i;
- for (i = 0; i<NO_SPARE_SOLARIS_FD; i++)
- m_lo_fd[i] = open("/dev/null", O_RDONLY);
-}
-
-int Yaz_Proxy::server(const char *addr)
-{
- int r = Yaz_Z_Assoc::server(addr);
- if (!r)
- {
- yaz_log(LOG_LOG, "%sStarted proxy " VERSION " on %s", m_session_str, addr);
- timeout(1);
- }
- return r;
-}
-
* Copyright (c) 2002-2004, Index Data.
* See the file LICENSE for details.
*
- * $Id: yaz-z-cache.cpp,v 1.8 2004-01-24 21:32:31 adam Exp $
+ * $Id: yaz-z-cache.cpp,v 1.9 2004-03-29 22:46:51 adam Exp $
*/
#include <yaz/log.h>
-#include <yaz++/proxy.h>
+#include <yaz/proto.h>
+#include <yaz++/record-cache.h>
struct Yaz_RecordCache_Entry {
int m_offset;
#!/bin/sh
-# $Id: yaz++-config.in,v 1.6 2004-02-11 10:05:19 adam Exp $
+# $Id: yaz++-config.in,v 1.7 2004-03-29 22:46:50 adam Exp $
yazppprefix=@prefix@
yaz_echo_cflags=no
yaz_echo_libs=no
exit $1
}
-#if test $# -eq 0; then
-# yaz_echo_help=yes
-#fi
+if test $# -eq 0; then
+ yaz_echo_help=yes
+fi
while test $# -gt 0; do
case "$1" in