From 28588b9224eb5189af32b10f440ef2a917a05ea2 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Wed, 1 Oct 2003 13:13:51 +0000 Subject: [PATCH] Proxy with QOS support. XML config. Better logging --- configure.in | 27 +++ include/yaz++/ir-assoc.h | 4 +- include/yaz++/pdu-assoc.h | 5 +- include/yaz++/pdu-observer.h | 4 +- include/yaz++/proxy.h | 76 +++++++- include/yaz++/z-assoc.h | 6 +- include/yaz++/z-query.h | 6 +- include/yaz++/z-server.h | 4 +- src/Makefile.am | 6 +- src/yaz-bw.cpp | 52 ++++++ src/yaz-ir-assoc.cpp | 23 ++- src/yaz-my-client.cpp | 4 +- src/yaz-pdu-assoc.cpp | 20 +- src/yaz-proxy-config.cpp | 219 ++++++++++++++++++++++ src/yaz-proxy-main.cpp | 32 +++- src/yaz-proxy.cpp | 423 ++++++++++++++++++++++++++++++++---------- src/yaz-z-assoc.cpp | 10 +- src/yaz-z-cache.cpp | 4 +- src/yaz-z-query.cpp | 128 ++++++++++++- src/yaz-z-server-ill.cpp | 4 +- src/yaz-z-server-sr.cpp | 6 +- src/yaz-z-server-update.cpp | 8 +- src/yaz-z-server.cpp | 8 +- 23 files changed, 914 insertions(+), 165 deletions(-) create mode 100644 src/yaz-bw.cpp create mode 100644 src/yaz-proxy-config.cpp diff --git a/configure.in b/configure.in index a954fef..96b3dce 100644 --- a/configure.in +++ b/configure.in @@ -11,6 +11,33 @@ AM_PROG_LIBTOOL YAZ_INIT(threads) dnl +dnl ----- libXML2 +AC_SUBST(XML2_LIBS) +AC_SUBST(XML2_CFLAGS) +xml2dir=yes +AC_ARG_WITH(xml2, [ --with-xml2[=PREFIX] use libxml2 in PREFIX],[xml2dir=$withval]) +if test "$xml2dir" = "yes"; then + for d in /usr /usr/local; do + if test -x $d/bin/xml2-config; then + xml2dir=$d + fi + done +fi +if test "$xml2dir" != "no"; then + AC_MSG_CHECKING(for libXML2) + if test -x $xml2dir/bin/xml2-config; then + XML2_LIBS=`$xml2dir/bin/xml2-config --libs` + LIBS="$XML2_LIBS $LIBS" + XML2_CFLAGS=`$xml2dir/bin/xml2-config --cflags` + XML2_VER=`$xml2dir/bin/xml2-config --version` + AC_MSG_RESULT($XML2_VER) + AC_DEFINE(HAVE_XML2) + else + AC_MSG_RESULT(Not found) + fi +fi + +dnl dnl ----- DOCBOOK DTD AC_SUBST(DTD_DIR) AC_ARG_WITH(dtd, [ --with-dtd[=DIR] Use docbookx.dtd in DIR], diff --git a/include/yaz++/ir-assoc.h b/include/yaz++/ir-assoc.h index 408f31f..aed30c6 100644 --- a/include/yaz++/ir-assoc.h +++ b/include/yaz++/ir-assoc.h @@ -2,7 +2,7 @@ * Copyright (c) 1998-2000, Index Data. * See the file LICENSE for details. * - * $Id: ir-assoc.h,v 1.1 2002-10-09 12:50:26 adam Exp $ + * $Id: ir-assoc.h,v 1.2 2003-10-01 13:13:51 adam Exp $ */ #include @@ -19,7 +19,7 @@ class YAZ_EXPORT Yaz_IR_Assoc: public Yaz_Z_Assoc { /// Destroy assocation and close PDU Observer virtual ~Yaz_IR_Assoc(); /// Receive Z39.50 PDU - void recv_Z_PDU(Z_APDU *apdu); + void recv_Z_PDU(Z_APDU *apdu, int len); /// Set Database Names void set_databaseNames (int num, const char **list); void set_databaseNames(const char *dblist, const char *sep); diff --git a/include/yaz++/pdu-assoc.h b/include/yaz++/pdu-assoc.h index e16c19f..fd217b4 100644 --- a/include/yaz++/pdu-assoc.h +++ b/include/yaz++/pdu-assoc.h @@ -1,8 +1,8 @@ /* - * Copyright (c) 1998-2000, Index Data. + * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: pdu-assoc.h,v 1.1 2002-10-09 12:50:26 adam Exp $ + * $Id: pdu-assoc.h,v 1.2 2003-10-01 13:13:51 adam Exp $ */ #ifndef YAZ_PDU_ASSOC_INCLUDED @@ -78,6 +78,7 @@ class YAZ_EXPORT Yaz_PDU_Assoc : public IYaz_PDU_Observable, IYazSocketObserver void idleTime (int timeout); /// Child start... virtual void childNotify(COMSTACK cs); + const char *getpeername(); }; class YAZ_EXPORT Yaz_PDU_AssocThread : public Yaz_PDU_Assoc { diff --git a/include/yaz++/pdu-observer.h b/include/yaz++/pdu-observer.h index 02b5fe8..d391189 100644 --- a/include/yaz++/pdu-observer.h +++ b/include/yaz++/pdu-observer.h @@ -2,7 +2,7 @@ * Copyright (c) 1998-2000, Index Data. * See the file LICENSE for details. * - * $Id: pdu-observer.h,v 1.1 2002-10-09 12:50:26 adam Exp $ + * $Id: pdu-observer.h,v 1.2 2003-10-01 13:13:51 adam Exp $ */ #ifndef YAZ_PDU_OBSERVER_H @@ -32,6 +32,8 @@ class YAZ_EXPORT IYaz_PDU_Observable { virtual void destroy() = 0; /// Set Idle Time virtual void idleTime (int timeout) = 0; + /// Get peername + virtual const char *getpeername() = 0; }; /** Protocol Data Unit Observer. diff --git a/include/yaz++/proxy.h b/include/yaz++/proxy.h index 54f93d3..dd86def 100644 --- a/include/yaz++/proxy.h +++ b/include/yaz++/proxy.h @@ -2,17 +2,43 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: proxy.h,v 1.7 2003-09-04 20:11:03 adam Exp $ + * $Id: proxy.h,v 1.8 2003-10-01 13:13:51 adam Exp $ */ #include #include #include +#if HAVE_XML2 +#include +#include +#endif + class Yaz_Proxy; struct Yaz_RecordCache_Entry; +class YAZ_EXPORT Yaz_ProxyConfig { +public: + Yaz_ProxyConfig(); + ~Yaz_ProxyConfig(); + int read_xml(const char *fname); + void get_target_info(const char *name, const char **url, int *keepalive, + int *limit_bw, int *limit_pdu, int *limit_req); + void operator=(const Yaz_ProxyConfig &conf); +private: +#if HAVE_XML2 + xmlDocPtr m_docPtr; + xmlNodePtr m_proxyPtr; + void return_target_info(xmlNodePtr ptr, const char **url, int *keepalive, + int *limit_bw, int *limit_pdu, int *limit_req); + void return_limit(xmlNodePtr ptr, + int *limit_bw, int *limit_pdu, int *limit_req); + const char *get_text(xmlNodePtr ptr); +#endif + int m_copy; +}; + class YAZ_EXPORT Yaz_RecordCache { public: Yaz_RecordCache (); @@ -35,12 +61,25 @@ class YAZ_EXPORT Yaz_RecordCache { Z_RecordComposition *comp); }; +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_ProxyClient(); - void recv_Z_PDU(Z_APDU *apdu); + void recv_Z_PDU(Z_APDU *apdu, int len); IYaz_PDU_Observer* sessionNotify (IYaz_PDU_Observable *the_PDU_Observable, int fd); void shutdown(); @@ -48,6 +87,8 @@ class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc { 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; @@ -61,6 +102,8 @@ class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc { int m_seqno; int m_waiting; int m_resultSetStartPoint; + int m_bytes_sent; + int m_bytes_recv; ODR m_init_odr; Z_APDU *m_initResponse; Yaz_RecordCache m_cache; @@ -82,25 +125,46 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { int m_seqno; int m_max_clients; int m_keepalive; - int m_idletime; + 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[20]; // session string (time:session_no) + Yaz_ProxyConfig m_config; + 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_APDU *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); public: Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable); ~Yaz_Proxy(); - void recv_Z_PDU(Z_APDU *apdu); + void recv_Z_PDU(Z_APDU *apdu, int len); + void recv_Z_PDU_0(Z_APDU *apdu); IYaz_PDU_Observer* sessionNotify (IYaz_PDU_Observable *the_PDU_Observable, int fd); void failNotify(); void timeoutNotify(); void connectNotify(); const char *option(const char *name, const char *value); - void set_proxy_target(const char *target); + 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_idletime (int t) { m_idletime = (t > 1) ? t : 600; }; + 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); + int send_to_client(Z_APDU *apdu); }; diff --git a/include/yaz++/z-assoc.h b/include/yaz++/z-assoc.h index 02c7302..ada736b 100644 --- a/include/yaz++/z-assoc.h +++ b/include/yaz++/z-assoc.h @@ -2,7 +2,7 @@ * Copyright (c) 1998-2000, Index Data. * See the file LICENSE for details. * - * $Id: z-assoc.h,v 1.1 2002-10-09 12:50:26 adam Exp $ + * $Id: z-assoc.h,v 1.2 2003-10-01 13:13:51 adam Exp $ */ #ifndef YAZ_Z_ASSOC_INCLUDED @@ -43,9 +43,9 @@ class YAZ_EXPORT Yaz_Z_Assoc : public IYaz_PDU_Observer { /// Encode Z39.50 PDU. int encode_Z_PDU(Z_APDU *apdu, char **buf, int *len); /// Send Z39.50 PDU - int send_Z_PDU(Z_APDU *apdu); + int send_Z_PDU(Z_APDU *apdu, int *len); /// Receive Z39.50 PDU - virtual void recv_Z_PDU(Z_APDU *apdu) = 0; + virtual void recv_Z_PDU(Z_APDU *apdu, int len) = 0; /// Create Z39.50 PDU with reasonable defaults Z_APDU *create_Z_PDU(int type); /// Request Alloc diff --git a/include/yaz++/z-query.h b/include/yaz++/z-query.h index ddc092d..57a2c44 100644 --- a/include/yaz++/z-query.h +++ b/include/yaz++/z-query.h @@ -2,7 +2,7 @@ * Copyright (c) 1998-2000, Index Data. * See the file LICENSE for details. * - * $Id: z-query.h,v 1.1 2002-10-09 12:50:26 adam Exp $ + * $Id: z-query.h,v 1.2 2003-10-01 13:13:51 adam Exp $ */ #include @@ -33,4 +33,8 @@ class YAZ_EXPORT Yaz_Z_Query : public Yaz_Query { ODR odr_decode; ODR odr_encode; ODR odr_print; + void oid2str(Odr_oid *o, WRBUF buf); + int rpn2pquery(Z_RPNStructure *s, WRBUF buf); + WRBUF zquery2pquery(Z_Query *q); + void pr_term(WRBUF wbuf, char *buf, int len); }; diff --git a/include/yaz++/z-server.h b/include/yaz++/z-server.h index 7880575..df4acc8 100644 --- a/include/yaz++/z-server.h +++ b/include/yaz++/z-server.h @@ -2,7 +2,7 @@ * Copyright (c) 2000-2001, Index Data. * See the file LICENSE for details. * - * $Id: z-server.h,v 1.2 2002-10-28 12:16:09 adam Exp $ + * $Id: z-server.h,v 1.3 2003-10-01 13:13:51 adam Exp $ */ #include @@ -119,7 +119,7 @@ class YAZ_EXPORT Yaz_Z_Server : public Yaz_Z_Assoc { public: Yaz_Z_Server(IYaz_PDU_Observable *the_PDU_Observable); virtual ~Yaz_Z_Server(); - virtual void recv_Z_PDU(Z_APDU *apdu); + virtual void recv_Z_PDU(Z_APDU *apdu, int len); void facility_add(IYaz_Server_Facility *facility, const char *name); void facility_reset (); diff --git a/src/Makefile.am b/src/Makefile.am index ff0b7fb..a318b44 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ -## $Id: Makefile.am,v 1.14 2003-07-18 13:27:20 adam Exp $ +## $Id: Makefile.am,v 1.15 2003-10-01 13:13:51 adam Exp $ -AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include +AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include $(XML2_CFLAGS) noinst_LTLIBRARIES = libyazcpp.la @@ -8,7 +8,7 @@ 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-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-z-cache.cpp yaz-proxy-config.cpp yaz-bw.cpp bin_PROGRAMS = yaz-proxy noinst_PROGRAMS = yaz-my-server yaz-my-client diff --git a/src/yaz-bw.cpp b/src/yaz-bw.cpp new file mode 100644 index 0000000..73d69e4 --- /dev/null +++ b/src/yaz-bw.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000-2003, Index Data. + * See the file LICENSE for details. + * + * $Id: yaz-bw.cpp,v 1.1 2003-10-01 13:13:51 adam Exp $ + */ + +#include +#include +#include + + +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) + 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; +} + diff --git a/src/yaz-ir-assoc.cpp b/src/yaz-ir-assoc.cpp index f8ca2d0..e0aaf7d 100644 --- a/src/yaz-ir-assoc.cpp +++ b/src/yaz-ir-assoc.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 1998-2000, Index Data. + * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-ir-assoc.cpp,v 1.18 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-ir-assoc.cpp,v 1.19 2003-10-01 13:13:51 adam Exp $ */ #include @@ -149,9 +149,9 @@ void Yaz_IR_Assoc::get_elementSetName (const char **elementSetName) *elementSetName = m_elementSetNames->u.generic; } -void Yaz_IR_Assoc::recv_Z_PDU(Z_APDU *apdu) +void Yaz_IR_Assoc::recv_Z_PDU(Z_APDU *apdu, int len) { - yaz_log (m_log, "recv_Z_PDU"); + yaz_log (m_log, "recv_Z_PDU %d bytes", len); m_lastReceived = apdu->which; switch (apdu->which) { @@ -227,7 +227,7 @@ int Yaz_IR_Assoc::send_searchRequest(Yaz_Z_Query *query, req->resultSetName = pResultSetId; } - return send_Z_PDU(apdu); + return send_Z_PDU(apdu, 0); } int Yaz_IR_Assoc::send_presentRequest(int start, @@ -276,7 +276,7 @@ int Yaz_IR_Assoc::send_presentRequest(int start, req->resultSetId = pResultSetId; } - return send_Z_PDU(apdu); + return send_Z_PDU(apdu, 0); } void Yaz_IR_Assoc::set_proxy(const char *str) @@ -330,19 +330,19 @@ const char *Yaz_IR_Assoc::get_host() void Yaz_IR_Assoc::recv_searchRequest(Z_SearchRequest *searchRequest) { Z_APDU *apdu = create_Z_PDU(Z_APDU_searchResponse); - send_Z_PDU(apdu); + send_Z_PDU(apdu, 0); } void Yaz_IR_Assoc::recv_presentRequest(Z_PresentRequest *presentRequest) { Z_APDU *apdu = create_Z_PDU(Z_APDU_presentResponse); - send_Z_PDU(apdu); + send_Z_PDU(apdu, 0); } void Yaz_IR_Assoc::recv_initRequest(Z_InitRequest *initRequest) { Z_APDU *apdu = create_Z_PDU(Z_APDU_initResponse); - send_Z_PDU(apdu); + send_Z_PDU(apdu, 0); } void Yaz_IR_Assoc::recv_searchResponse (Z_SearchResponse *searchResponse) @@ -398,7 +398,7 @@ int Yaz_IR_Assoc::send_initRequest(char* pRefId) set_otherInformationString(&req->otherInfo, VAL_PROXY, 1, m_host); if (m_cookie) set_otherInformationString(&req->otherInfo, VAL_COOKIE, 1, m_cookie); - return send_Z_PDU(apdu); + return send_Z_PDU(apdu, 0); } int Yaz_IR_Assoc::send_deleteResultSetRequest(char* pResultSetId, char* pRefId) @@ -430,8 +430,7 @@ int Yaz_IR_Assoc::send_deleteResultSetRequest(char* pResultSetId, char* pRefId) if (m_cookie) set_otherInformationString(&req->otherInfo, VAL_COOKIE, 1, m_cookie); - - return send_Z_PDU(apdu); + return send_Z_PDU(apdu, 0); } diff --git a/src/yaz-my-client.cpp b/src/yaz-my-client.cpp index 0df0b00..4ad8319 100644 --- a/src/yaz-my-client.cpp +++ b/src/yaz-my-client.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 1998-2001, Index Data. + * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-my-client.cpp,v 1.12 2002-10-28 12:16:09 adam Exp $ + * $Id: yaz-my-client.cpp,v 1.13 2003-10-01 13:13:51 adam Exp $ */ #include diff --git a/src/yaz-pdu-assoc.cpp b/src/yaz-pdu-assoc.cpp index bcdeded..a7fc349 100644 --- a/src/yaz-pdu-assoc.cpp +++ b/src/yaz-pdu-assoc.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2001, Index Data. * See the file LICENSE for details. * - * $Id: yaz-pdu-assoc.cpp,v 1.29 2003-07-25 19:27:36 adam Exp $ + * $Id: yaz-pdu-assoc.cpp,v 1.30 2003-10-01 13:13:51 adam Exp $ */ #include @@ -433,8 +433,17 @@ void Yaz_PDU_Assoc::connect(IYaz_PDU_Observer *observer, res); m_socketObservable->addObserver(cs_fileno(m_cs), this); - if (res >= 0) - { // Connect pending or complete + if (res == 0) + { // Connect complete + m_state = Connecting; + unsigned mask = YAZ_SOCKET_OBSERVE_EXCEPT; + mask |= YAZ_SOCKET_OBSERVE_WRITE; + mask |= YAZ_SOCKET_OBSERVE_READ; + yaz_log(m_log, "maskObserver 11"); + m_socketObservable->maskObserver(this, mask); + } + else if (res > 0) + { // Connect pending m_state = Connecting; unsigned mask = YAZ_SOCKET_OBSERVE_EXCEPT; if (m_cs->io_pending & CS_WANT_WRITE) @@ -468,3 +477,8 @@ void Yaz_PDU_Assoc::childNotify(COMSTACK cs) new_observable->m_PDU_Observer = m_PDU_Observer->sessionNotify (new_observable, cs_fileno(cs)); } + +const char*Yaz_PDU_Assoc::getpeername() +{ + return cs_addrstr(m_cs); +} diff --git a/src/yaz-proxy-config.cpp b/src/yaz-proxy-config.cpp new file mode 100644 index 0000000..61cfb8d --- /dev/null +++ b/src/yaz-proxy-config.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1998-2003, Index Data. + * See the file LICENSE for details. + * + * $Id: yaz-proxy-config.cpp,v 1.1 2003-10-01 13:13:51 adam Exp $ + */ + +#include +#include + +Yaz_ProxyConfig::Yaz_ProxyConfig() +{ + m_copy = 0; +#if HAVE_XML2 + m_docPtr = 0; + m_proxyPtr = 0; +#endif +} + +Yaz_ProxyConfig::~Yaz_ProxyConfig() +{ +#if HAVE_XML2 + if (!m_copy && m_docPtr) + xmlFreeDoc(m_docPtr); +#endif +} + +void Yaz_ProxyConfig::operator=(const Yaz_ProxyConfig &conf) +{ +#if HAVE_XML2 + m_docPtr = conf.m_docPtr; + m_proxyPtr = conf.m_proxyPtr; +#endif + m_copy = 1; +} + +int Yaz_ProxyConfig::read_xml(const char *fname) +{ +#if HAVE_XML2 + 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_XML2 +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_XML2 +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_XML2 +void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr, + const char **url, + int *keepalive, + int *limit_bw, + int *limit_pdu, + int *limit_req) +{ + ptr = ptr->children; + for (; ptr; ptr = ptr->next) + { + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "url")) + { + const char *t = get_text(ptr); + if (t) + *url = t; + } + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "keepalive")) + { + const char *t = get_text(ptr); + if (!t || *t == '1') + *keepalive = 1; + else + *keepalive = 0; + } + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "limit")) + return_limit(ptr, limit_bw, limit_pdu, limit_req); + } +} +#endif + +void Yaz_ProxyConfig::get_target_info(const char *name, + const char **url, + int *keepalive, + int *limit_bw, + int *limit_pdu, + int *limit_req) +{ +#if HAVE_XML2 + xmlNodePtr ptr; + if (!m_proxyPtr) + { + *url = name; + return; + } + 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) + { + // ? + 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_target_info(ptr, url, keepalive, + limit_bw, limit_pdu, limit_req); + return; + } + } + } + else + { + // ? + 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, + "*"))) + { + *url = name; + return_target_info(ptr, url, keepalive, + limit_bw, limit_pdu, limit_req); + return; + } + } + } + } + } +#else + *url = name; + return; +#endif +} + + diff --git a/src/yaz-proxy-main.cpp b/src/yaz-proxy-main.cpp index 9b7ffc5..a7faf3b 100644 --- a/src/yaz-proxy-main.cpp +++ b/src/yaz-proxy-main.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2001, Index Data. * See the file LICENSE for details. * - * $Id: yaz-proxy-main.cpp,v 1.18 2002-10-23 10:15:18 adam Exp $ + * $Id: yaz-proxy-main.cpp,v 1.19 2003-10-01 13:13:51 adam Exp $ */ #include @@ -14,7 +14,7 @@ void usage(char *prog) { - fprintf (stderr, "%s: [-a log] [-c num] [-v level] [-t target] [-i sec] " + fprintf (stderr, "%s: [-c config] [-a log] [-m num] [-v level] [-t target] [-i sec] " "[-u auth] [-o optlevel] @:port\n", prog); exit (1); } @@ -27,8 +27,9 @@ int args(Yaz_Proxy *proxy, int argc, char **argv) char *prog = argv[0]; int ret; - while ((ret = options("o:a:t:v:c:u:i:", argv, argc, &arg)) != -2) + while ((ret = options("o:a:t:v:c:u:i:m:l:T:", argv, argc, &arg)) != -2) { + int err; switch (ret) { case 0: @@ -39,11 +40,24 @@ int args(Yaz_Proxy *proxy, int argc, char **argv) } 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_proxy_target(arg); + proxy->set_default_target(arg); break; case 'u': proxy->set_proxy_authentication(arg); @@ -54,11 +68,17 @@ int args(Yaz_Proxy *proxy, int argc, char **argv) case 'v': yaz_log_init_level (yaz_log_mask_str(arg)); break; - case 'c': + case 'l': + yaz_log_init_file (arg); + break; + case 'm': proxy->set_max_clients(atoi(arg)); break; case 'i': - proxy->set_idletime(atoi(arg)); + proxy->set_client_idletime(atoi(arg)); + break; + case 'T': + proxy->set_target_idletime(atoi(arg)); break; default: usage(prog); diff --git a/src/yaz-proxy.cpp b/src/yaz-proxy.cpp index ab518e7..81e987e 100644 --- a/src/yaz-proxy.cpp +++ b/src/yaz-proxy.cpp @@ -2,45 +2,103 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-proxy.cpp,v 1.47 2003-09-03 11:30:26 adam Exp $ + * $Id: yaz-proxy.cpp,v 1.48 2003-10-01 13:13:51 adam Exp $ */ #include #include #include +#include #include +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"; +} + + Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) : - Yaz_Z_Assoc(the_PDU_Observable) + 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 = 0; m_clientPool = 0; m_seqno = 1; - m_keepalive = 1; + m_keepalive = 0; m_proxyTarget = 0; + m_default_target = 0; m_proxy_authentication = 0; m_max_clients = 150; m_seed = time(0); - m_idletime = 600; + m_client_idletime = 600; + m_target_idletime = 600; m_optimize = xstrdup ("1"); + strcpy(m_session_str, "x"); + m_session_no=0; + m_bytes_sent = m_bytes_recv = 0; + m_bw_hold_PDU = 0; + m_bw_max = 0; + m_pdu_max = 0; + m_max_record_retrieve = 0; } Yaz_Proxy::~Yaz_Proxy() { + yaz_log(LOG_LOG, "%s Closed %d/%d sent/recv bytes total", m_session_str, + m_bytes_sent, m_bytes_recv); xfree (m_proxyTarget); + xfree (m_default_target); xfree (m_proxy_authentication); xfree (m_optimize); } -void Yaz_Proxy::set_proxy_target(const char *target) +int Yaz_Proxy::set_config(const char *config) { - xfree (m_proxyTarget); - m_proxyTarget = 0; + int r = m_config.read_xml(config); + return r; +} + +void Yaz_Proxy::set_default_target(const char *target) +{ + xfree (m_default_target); + m_default_target = 0; if (target) - m_proxyTarget = (char *) xstrdup (target); + m_default_target = (char *) xstrdup (target); } void Yaz_Proxy::set_proxy_authentication (const char *auth) @@ -56,11 +114,16 @@ IYaz_PDU_Observer *Yaz_Proxy::sessionNotify(IYaz_PDU_Observable { Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable); new_proxy->m_parent = this; - new_proxy->timeout(m_idletime); - new_proxy->set_proxy_target(m_proxyTarget); + new_proxy->m_config = m_config; + new_proxy->timeout(m_client_idletime); + new_proxy->m_target_idletime = m_target_idletime; + new_proxy->set_default_target(m_default_target); new_proxy->set_APDU_log(get_APDU_log()); new_proxy->set_proxy_authentication(m_proxy_authentication); - yaz_log (LOG_LOG, "New session p=%p", new_proxy); + sprintf(new_proxy->m_session_str, "%ld:%d", (long) time(0), m_session_no); + m_session_no++; + yaz_log (LOG_LOG, "%s New session %s", new_proxy->m_session_str, + the_PDU_Observable->getpeername()); return new_proxy; } @@ -106,16 +169,23 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) get_otherInfoAPDU(apdu, &oi); char *cookie = get_cookie(oi); - const char *proxy_host = get_proxy(oi); - if (proxy_host) - set_proxy_target(proxy_host); - - // no target specified at all? if (!m_proxyTarget) - return 0; - - if (!strcmp(m_proxyTarget, "stop")) - exit (0); + { + const char *proxy_host = get_proxy(oi); + if (!proxy_host) + proxy_host = m_default_target; + + const char *url = 0; + m_config.get_target_info(proxy_host, &url, &m_keepalive, &m_bw_max, + &m_pdu_max, &m_max_record_retrieve); + + if (!url) + { + yaz_log(LOG_LOG, "%s No default target", m_session_str); + return 0; + } + m_proxyTarget = (char*) xstrdup(url); + } if (cookie && *cookie) { Yaz_ProxyClient *cc = 0; @@ -139,7 +209,8 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) // we have an initRequest we can safely do re-open if (c->m_waiting && apdu->which == Z_APDU_initRequest) { - yaz_log (LOG_LOG, "reopen target=%s", c->get_hostname()); + yaz_log (LOG_LOG, "%s REOPEN target=%s", m_session_str, + c->get_hostname()); c->close(); c->client(m_proxyTarget); c->m_init_flag = 0; @@ -150,7 +221,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) c->m_sr_transform = 0; c->m_waiting = 0; c->m_resultSetStartPoint = 0; - c->timeout(m_idletime); + c->timeout(m_target_idletime); } c->m_seqno = parent->m_seqno; if (c->m_server && c->m_server != this) @@ -180,7 +251,8 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) // found it in cache c = cc; - yaz_log (LOG_LOG, "Reuse session %d to %d %s", + yaz_log (LOG_LOG, "%s REUSE %d %d %s", + m_session_str, c->m_seqno, parent->m_seqno, c->get_hostname()); c->m_seqno = parent->m_seqno; @@ -238,16 +310,17 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) c = c_min; if (c->m_waiting || strcmp(m_proxyTarget, c->get_hostname())) { - yaz_log (LOG_LOG, "Replace session %d", - c->m_seqno); + yaz_log (LOG_LOG, "%s MAXCLIENTS Destroy %d", + m_session_str, c->m_seqno); if (c->m_server && c->m_server != this) delete c->m_server; c->m_server = 0; } else { - yaz_log (LOG_LOG, "Move session %d to %d %s", - c->m_seqno, parent->m_seqno, c->get_hostname()); + yaz_log (LOG_LOG, "%s MAXCLIENTS Reuse %d %d %s", + m_session_str, + c->m_seqno, parent->m_seqno, c->get_hostname()); xfree (c->m_cookie); c->m_cookie = 0; if (cookie) @@ -259,14 +332,13 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) delete c->m_server; } (parent->m_seqno)++; - yaz_log (LOG_DEBUG, "get_client 2 %p %p", this, c); return c; } } else { - yaz_log (LOG_LOG, "Making session %d %s", parent->m_seqno, - m_proxyTarget); + yaz_log (LOG_LOG, "%s NEW %d %s", + m_session_str, parent->m_seqno, m_proxyTarget); c = new Yaz_ProxyClient(m_PDU_Observable->clone()); c->m_next = parent->m_clientPool; if (c->m_next) @@ -280,7 +352,6 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) if (cookie) c->m_cookie = xstrdup(cookie); - yaz_log (LOG_LOG, "Connecting to %s", m_proxyTarget); c->m_seqno = parent->m_seqno; c->client(m_proxyTarget); c->m_init_flag = 0; @@ -290,7 +361,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) c->m_sr_transform = 0; c->m_waiting = 0; c->m_resultSetStartPoint = 0; - c->timeout(20); + c->timeout(30); (parent->m_seqno)++; } @@ -298,6 +369,96 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) return c; } +void Yaz_Proxy::display_diagrecs(Z_DiagRec **pp, int num) +{ + int i; + for (i = 0; iwhich != Z_DiagRec_defaultFormat) + { + yaz_log(LOG_LOG, "%s Error 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, "%s Error unknown diagnostic set", m_session_str); + switch (r->which) + { + case Z_DefaultDiagFormat_v2Addinfo: + yaz_log(LOG_LOG, "%s Error %d %s:%s", + m_session_str, + *r->condition, diagbib1_str(*r->condition), + r->u.v2Addinfo); + break; + case Z_DefaultDiagFormat_v3Addinfo: + yaz_log(LOG_LOG, "%s Error %d %s:%s", + m_session_str, + *r->condition, diagbib1_str(*r->condition), + r->u.v3Addinfo); + break; + } + } +} + +int Yaz_Proxy::send_to_client(Z_APDU *apdu) +{ + int len = 0; + 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; + + display_diagrecs(&dr_p, 1); + } + else + { + if (sr->resultCount) + yaz_log(LOG_LOG, "%s %d hits", m_session_str, + *sr->resultCount); + } + } + 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; + + display_diagrecs(&dr_p, 1); + } + } + int r = send_Z_PDU(apdu, &len); + yaz_log (LOG_LOG, "%s Sending %s to client %d bytes", m_session_str, + apdu_name(apdu), len); + m_bytes_sent += len; + m_bw_stat.add_bytes(len); + return r; +} + +int Yaz_ProxyClient::send_to_target(Z_APDU *apdu) +{ + int len = 0; + int r = send_Z_PDU(apdu, &len); + yaz_log (LOG_LOG, "%s Sending %s to %s %d bytes", + get_session_str(), + apdu_name(apdu), get_hostname(), len); + m_bytes_sent += len; + return r; +} + Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) { if (*m_parent->m_optimize == '0') @@ -316,7 +477,8 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) pr->preferredRecordSyntax, pr->recordComposition)) { - yaz_log (LOG_LOG, "Returned cache records for present request"); + yaz_log (LOG_LOG, "%s Returned cache records for present request", + m_session_str); Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentResponse); new_apdu->u.presentResponse->referenceId = pr->referenceId; @@ -329,7 +491,8 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) new_apdu->u.presentResponse->records->u.databaseOrSurDiagnostics = npr; new_apdu->u.presentResponse->nextResultSetPosition = odr_intdup(odr_encode(), start+toget); - send_Z_PDU(new_apdu); + + send_to_client(new_apdu); return 0; } } @@ -345,7 +508,11 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) sr->databaseNames); this_query->set_Z_Query(sr->query); - + + char query_str[80]; + this_query->print(query_str, sizeof(query_str)-1); + yaz_log(LOG_LOG, "%s Query %s", m_session_str, query_str); + if (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) && @@ -373,7 +540,8 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget, sr->preferredRecordSyntax, comp)) { - yaz_log (LOG_LOG, "Returned cache records for medium set"); + yaz_log (LOG_LOG, "%s Returned cache 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 = @@ -390,14 +558,15 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr; new_apdu->u.searchResponse->nextResultSetPosition = odr_intdup(odr_encode(), toget+1); - send_Z_PDU(new_apdu); + send_to_client(new_apdu); return 0; } else { // medium Set // send present request (medium size) - yaz_log (LOG_LOG, "Optimizing search for medium set"); + yaz_log (LOG_LOG, "%s Optimizing search for medium set", + m_session_str); Z_APDU *new_apdu = create_Z_PDU(Z_APDU_presentRequest); Z_PresentRequest *pr = new_apdu->u.presentRequest; @@ -414,12 +583,13 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) m_client->m_last_resultCount <= 0) { // large set. Return pseudo-search response immediately - yaz_log (LOG_LOG, "Optimizing search for large set"); + yaz_log (LOG_LOG, "%s Optimizing 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_Z_PDU(new_apdu); + send_to_client(new_apdu); return 0; } else @@ -441,7 +611,8 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) if (m_client->m_cache.lookup (odr_encode(), &npr, 1, toget, sr->preferredRecordSyntax, comp)) { - yaz_log (LOG_LOG, "Returned cache records for small set"); + yaz_log (LOG_LOG, "%s Returned cache 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 = @@ -458,12 +629,13 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) new_apdu->u.searchResponse->records->u.databaseOrSurDiagnostics = npr; new_apdu->u.searchResponse->nextResultSetPosition = odr_intdup(odr_encode(), toget+1); - send_Z_PDU(new_apdu); + send_to_client(new_apdu); return 0; } else { - yaz_log (LOG_LOG, "Optimizing search for small set"); + yaz_log (LOG_LOG, "%s Optimizing 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; @@ -493,47 +665,67 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) return apdu; } -static const char *apdu_name(Z_APDU *apdu) + +void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu, int len) { - switch (apdu->which) + int reduce = 0; + m_bytes_recv += len; + + yaz_log (LOG_LOG, "%s Receiving %s from client %d bytes", m_session_str, + apdu_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); + + int bw_total = m_bw_stat.get_total(); + int pdu_total = m_pdu_stat.get_total(); + + yaz_log(LOG_LOG, "%s stat bw=%d pdu=%d limit-bw=%d limit-pdu=%d", + m_session_str, bw_total, pdu_total, m_bw_max, m_pdu_max); + if (m_bw_max) { - 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"; + if (bw_total > m_bw_max) + { + reduce = (bw_total/m_bw_max); + } } - return "other"; + if (m_pdu_max) + { + if (pdu_total > m_pdu_max) + { + int nreduce = (60/m_pdu_max); + reduce = (reduce > nreduce) ? reduce : nreduce; + } + } + if (reduce) + { + yaz_log(LOG_LOG, "%s Limit delay=%d", m_session_str, reduce); + m_bw_hold_PDU = apdu; // save PDU and signal "on hold" + timeout(reduce); // call us reduce seconds later + } + else + recv_Z_PDU_0(apdu); // all fine. Proceed receive PDU as usual } -void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu) +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; + } + } +} + +void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu) { - yaz_log (LOG_LOG, "Receiving %s from client", apdu_name(apdu)); // Determine our client. m_client = get_client(apdu); if (!m_client) @@ -552,18 +744,17 @@ void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu) if (m_client->m_cookie && *m_client->m_cookie) set_otherInformationString(apdu, VAL_COOKIE, 1, m_client->m_cookie); - send_Z_PDU(apdu); + send_to_client(apdu); return; } m_client->m_init_flag = 1; } + handle_max_record_retrieve(apdu); + apdu = result_set_optimize(apdu); if (!apdu) return; - yaz_log (LOG_LOG, "Sending %s to %s", - apdu_name(apdu), m_client->get_hostname()); - // delete other info part from PDU before sending to target Z_OtherInformation **oi; get_otherInfoAPDU(apdu, &oi); @@ -579,7 +770,7 @@ void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu) } else { m_client->m_resultSetStartPoint = 0; } - if (m_client->send_Z_PDU(apdu) < 0) + if (m_client->send_to_target(apdu) < 0) { delete m_client; m_client = 0; @@ -598,7 +789,8 @@ void Yaz_Proxy::shutdown() // only keep if keep_alive flag is set... if (m_keepalive && m_client && m_client->m_waiting == 0) { - yaz_log (LOG_LOG, "shutdown (client to proxy) keepalive %s", + yaz_log (LOG_LOG, "%s Shutdown (client to proxy) keepalive %s", + m_session_str, m_client->get_hostname()); assert (m_client->m_waiting != 2); // Tell client (if any) that no server connection is there.. @@ -606,46 +798,65 @@ void Yaz_Proxy::shutdown() } else if (m_client) { - yaz_log (LOG_LOG, "shutdown (client to proxy) close %s", + yaz_log (LOG_LOG, "%s Shutdown (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, "shutdown (client to proxy) bad state"); + yaz_log (LOG_LOG, "%s shutdown (client to proxy) bad state", + m_session_str); assert (m_parent); } else { - yaz_log (LOG_LOG, "shutdown (client to proxy)"); + yaz_log (LOG_LOG, "%s Shutdown (client to proxy)", + m_session_str); } 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, "shutdown (proxy to server) %s", get_hostname()); + yaz_log (LOG_LOG, "%s Shutdown (proxy to target) %s", get_session_str(), + get_hostname()); delete m_server; delete this; } void Yaz_Proxy::failNotify() { - yaz_log (LOG_LOG, "Yaz_Proxy connection closed by client"); + yaz_log (LOG_LOG, "%s Connection closed by client", + get_session_str()); shutdown(); } void Yaz_ProxyClient::failNotify() { - yaz_log (LOG_LOG, "Yaz_ProxyClient connection closed by %s", get_hostname()); + yaz_log (LOG_LOG, "%s Connection closed by target %s", + get_session_str(), get_hostname()); shutdown(); } void Yaz_ProxyClient::connectNotify() { - yaz_log (LOG_LOG, "Connection accepted by %s", get_hostname()); - timeout(600); + yaz_log (LOG_LOG, "%s Connection accepted by %s", get_session_str(), + get_hostname()); + int to; + if (m_server) + to = m_server->get_target_idletime(); + else + to = 600; + timeout(to); } IYaz_PDU_Observer *Yaz_ProxyClient::sessionNotify(IYaz_PDU_Observable @@ -669,13 +880,24 @@ Yaz_ProxyClient::~Yaz_ProxyClient() void Yaz_Proxy::timeoutNotify() { - yaz_log (LOG_LOG, "timeout (client to proxy)"); - shutdown(); + if (m_bw_hold_PDU) + { + timeout(m_client_idletime); + Z_APDU *apdu = m_bw_hold_PDU; + m_bw_hold_PDU = 0; + recv_Z_PDU_0(apdu); + } + else + { + yaz_log (LOG_LOG, "%s Timeout (client to proxy)", m_session_str); + shutdown(); + } } void Yaz_ProxyClient::timeoutNotify() { - yaz_log (LOG_LOG, "timeout (proxy to target) %s", get_hostname()); + yaz_log (LOG_LOG, "%s Timeout (proxy to target) %s", get_session_str(), + get_hostname()); shutdown(); } @@ -695,6 +917,7 @@ Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable) : m_init_odr = odr_createmem (ODR_DECODE); m_initResponse = 0; m_resultSetStartPoint = 0; + m_bytes_sent = m_bytes_recv = 0; } const char *Yaz_Proxy::option(const char *name, const char *value) @@ -709,11 +932,12 @@ const char *Yaz_Proxy::option(const char *name, const char *value) return 0; } -void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu) +void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len) { + m_bytes_recv += len; m_waiting = 0; - yaz_log (LOG_LOG, "Receiving %s from %s", apdu_name(apdu), - get_hostname()); + yaz_log (LOG_LOG, "%s Receiving %s from %s %d bytes", get_session_str(), + apdu_name(apdu), get_hostname(), len); if (apdu->which == Z_APDU_initResponse) { NMEM nmem = odr_extract_mem (odr_decode()); @@ -766,8 +990,7 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu) set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie); if (m_server) { - yaz_log (LOG_LOG, "Sending %s to client", apdu_name(apdu)); - m_server->send_Z_PDU(apdu); + m_server->send_to_client(apdu); } if (apdu->which == Z_APDU_close) { diff --git a/src/yaz-z-assoc.cpp b/src/yaz-z-assoc.cpp index 2761220..91b47ce 100644 --- a/src/yaz-z-assoc.cpp +++ b/src/yaz-z-assoc.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2001, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-assoc.cpp,v 1.25 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-z-assoc.cpp,v 1.26 2003-10-01 13:13:51 adam Exp $ */ #include @@ -78,7 +78,7 @@ void Yaz_Z_Assoc::recv_PDU(const char *buf, int len) Z_APDU *apdu = decode_Z_PDU (buf, len); if (apdu) { - recv_Z_PDU (apdu); + recv_Z_PDU (apdu, len); } else { @@ -169,12 +169,16 @@ void Yaz_Z_Assoc::transfer_referenceId(Z_APDU *from, Z_APDU *to) *id_to = 0; } -int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu) +int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu, int *plen) { char *buf; int len; if (encode_Z_PDU(apdu, &buf, &len) > 0) + { + if (plen) + *plen = len; return m_PDU_Observable->send_PDU(buf, len); + } return -1; } diff --git a/src/yaz-z-cache.cpp b/src/yaz-z-cache.cpp index 8571410..8e521e6 100644 --- a/src/yaz-z-cache.cpp +++ b/src/yaz-z-cache.cpp @@ -2,7 +2,7 @@ * Copyright (c) 2002-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-cache.cpp,v 1.4 2003-08-28 18:46:54 adam Exp $ + * $Id: yaz-z-cache.cpp,v 1.5 2003-10-01 13:13:51 adam Exp $ */ #include @@ -160,7 +160,7 @@ int Yaz_RecordCache::lookup (ODR o, Z_NamePlusRecordList **npr, Z_RecordComposition *comp) { int i; - yaz_log(LOG_LOG, "cache lookup start=%d num=%d", start, num); + yaz_log(LOG_DEBUG, "cache lookup start=%d num=%d", start, num); for (i = 0; i @@ -52,7 +52,8 @@ Z_Query *Yaz_Z_Query::get_Z_Query () Z_Query *query; if (!buf) return 0; - odr_setbuf (odr_decode, buf, len, 0); + odr_reset(odr_decode); + odr_setbuf(odr_decode, buf, len, 0); if (!z_Query(odr_decode, &query, 0, 0)) return 0; return query; @@ -60,7 +61,26 @@ Z_Query *Yaz_Z_Query::get_Z_Query () void Yaz_Z_Query::print(char *str, int len) { - + Z_Query *query; + *str = 0; + if (!buf) + return; + odr_setbuf (odr_decode, buf, len, 0); + if (!z_Query(odr_decode, &query, 0, 0)) + return; + WRBUF wbuf = zquery2pquery(query); + if (wbuf) + { + if (wrbuf_len(wbuf) > len-1) + { + memcpy(str, wrbuf_buf(wbuf), len-1); + str[len-1] = '\0'; + } + else + strcpy(str, wrbuf_buf(wbuf)); + } + odr_reset(odr_decode); + wrbuf_free(wbuf,1); } int Yaz_Z_Query::match(Yaz_Z_Query *other) @@ -73,3 +93,103 @@ int Yaz_Z_Query::match(Yaz_Z_Query *other) return 0; return 1; } + +void Yaz_Z_Query::oid2str(Odr_oid *o, WRBUF buf) +{ + for (; *o >= 0; o++) { + char ibuf[16]; + sprintf(ibuf, "%d", *o); + wrbuf_puts(buf, ibuf); + if (o[1] > 0) + wrbuf_putc(buf, '.'); + } +} + +void Yaz_Z_Query::pr_term(WRBUF wbuf, char *buf, int len) +{ + int i; + wrbuf_putc(wbuf, '"'); + for (i = 0; iwhich == Z_RPNStructure_simple) + { + Z_Operand *o = s->u.simple; + + if (o->which == Z_Operand_APT) + { + Z_AttributesPlusTerm *at = s->u.simple->u.attributesPlusTerm; + if (at->attributes) { + int i; + for (i = 0; i < at->attributes->num_attributes; i++) { + wrbuf_puts(buf, "@attr "); + if (at->attributes->attributes[i]->attributeSet) { + oid2str(at->attributes->attributes[i]->attributeSet, buf); + wrbuf_putc(buf, ' '); + } + wrbuf_printf(buf, "%d=", *at->attributes->attributes[i]->attributeType); + wrbuf_printf(buf, "%d ", *at->attributes->attributes[i]->value.numeric); + } + } + if (at->term->which == Z_Term_general) + { + pr_term(buf, (char*) at->term->u.general->buf, + at->term->u.general->len); + } + else if (at->term->which == Z_Term_characterString) + { + wrbuf_puts(buf, "@term string "); + pr_term(buf, at->term->u.characterString, + strlen(at->term->u.characterString)); + + } + } + else if (o->which == Z_Operand_resultSetId) + { + wrbuf_printf(buf, "@set %s ", o->u.resultSetId); + } + } + else if (s->which == Z_RPNStructure_complex) + { + Z_Complex *c = s->u.complex; + + switch (c->roperator->which) { + case Z_Operator_and: wrbuf_puts(buf, "@and "); break; + case Z_Operator_or: wrbuf_puts(buf, "@or "); break; + case Z_Operator_and_not: wrbuf_puts(buf, "@not "); break; + case Z_Operator_prox: wrbuf_puts(buf, "@prox "); break; + default: wrbuf_puts(buf, "@unknown "); + } + if (!rpn2pquery(c->s1, buf)) + return 0; + if (!rpn2pquery(c->s2, buf)) + return 0; + } + return 1; +} + +WRBUF Yaz_Z_Query::zquery2pquery(Z_Query *q) +{ + WRBUF buf = wrbuf_alloc(); + + if (q->which != Z_Query_type_1 && q->which != Z_Query_type_101) + return 0; + if (q->u.type_1->attributeSetId) { + /* Output attribute set ID */ + wrbuf_puts(buf, "@attrset "); + oid2str(q->u.type_1->attributeSetId, buf); + wrbuf_putc(buf, ' '); + } + return rpn2pquery(q->u.type_1->RPNStructure, buf) ? buf : 0; +} + + diff --git a/src/yaz-z-server-ill.cpp b/src/yaz-z-server-ill.cpp index 3c42fb7..a9f23ce 100644 --- a/src/yaz-z-server-ill.cpp +++ b/src/yaz-z-server-ill.cpp @@ -2,7 +2,7 @@ * Copyright (c) 2000-2001, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-server-ill.cpp,v 1.8 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-z-server-ill.cpp,v 1.9 2003-10-01 13:13:51 adam Exp $ */ #include @@ -34,6 +34,6 @@ int Yaz_Facility_ILL::recv(Yaz_Z_Server *s, Z_APDU *apdu_request) ill_service(req, req->taskSpecificParameters->u.itemOrder, apdu_response->u.extendedServicesResponse); s->transfer_referenceId(apdu_request, apdu_response); - s->send_Z_PDU(apdu_response); + s->send_Z_PDU(apdu_response, 0); return 1; } diff --git a/src/yaz-z-server-sr.cpp b/src/yaz-z-server-sr.cpp index cb0671b..680248a 100644 --- a/src/yaz-z-server-sr.cpp +++ b/src/yaz-z-server-sr.cpp @@ -2,7 +2,7 @@ * Copyright (c) 2000-2001, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-server-sr.cpp,v 1.5 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-z-server-sr.cpp,v 1.6 2003-10-01 13:13:51 adam Exp $ * */ @@ -230,7 +230,7 @@ int Yaz_Facility_Retrieval::recv(Yaz_Z_Server *s, Z_APDU *apdu_request) fetch_via_piggyback(s, apdu_request->u.searchRequest, apdu_response->u.searchResponse); } - s->send_Z_PDU(apdu_response); + s->send_Z_PDU(apdu_response, 0); return 1; case Z_APDU_presentRequest: yaz_log (LOG_LOG, "got PresentRequest p=%p", this); @@ -241,7 +241,7 @@ int Yaz_Facility_Retrieval::recv(Yaz_Z_Server *s, Z_APDU *apdu_request) if (!apdu_response->u.presentResponse->records) fetch_via_present(s, apdu_request->u.presentRequest, apdu_response->u.presentResponse); - s->send_Z_PDU(apdu_response); + s->send_Z_PDU(apdu_response, 0); return 1; } return 0; diff --git a/src/yaz-z-server-update.cpp b/src/yaz-z-server-update.cpp index ddd30f8..ccfacf1 100644 --- a/src/yaz-z-server-update.cpp +++ b/src/yaz-z-server-update.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2001, Index Data. + * Copyright (c) 2000-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-server-update.cpp,v 1.4 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-z-server-update.cpp,v 1.5 2003-10-01 13:13:51 adam Exp $ */ #include @@ -34,7 +34,7 @@ int Yaz_Facility_Update::recv(Yaz_Z_Server *s, Z_APDU *apdu_request) update_service(req, req->taskSpecificParameters->u.update, apdu_response->u.extendedServicesResponse); s->transfer_referenceId(apdu_request, apdu_response); - s->send_Z_PDU(apdu_response); + s->send_Z_PDU(apdu_response, 0); } else if (req->taskSpecificParameters && req->taskSpecificParameters->which == Z_External_update0) @@ -44,7 +44,7 @@ int Yaz_Facility_Update::recv(Yaz_Z_Server *s, Z_APDU *apdu_request) update_service0 (req, req->taskSpecificParameters->u.update0, apdu_response->u.extendedServicesResponse); s->transfer_referenceId(apdu_request, apdu_response); - s->send_Z_PDU(apdu_response); + s->send_Z_PDU(apdu_response, 0); } return 1; } diff --git a/src/yaz-z-server.cpp b/src/yaz-z-server.cpp index 10aba4d..dff2815 100644 --- a/src/yaz-z-server.cpp +++ b/src/yaz-z-server.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2001, Index Data. + * Copyright (c) 2000-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-server.cpp,v 1.15 2002-10-09 12:50:26 adam Exp $ + * $Id: yaz-z-server.cpp,v 1.16 2003-10-01 13:13:51 adam Exp $ */ #include @@ -48,7 +48,7 @@ void Yaz_Z_Server::facility_add(IYaz_Server_Facility *facility, (*p)->m_facility = facility; } -void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request) +void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request, int len) { Yaz_Z_Server_Facility_Info *f = m_facilities; @@ -77,7 +77,7 @@ void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request) f = f->m_next; } transfer_referenceId(apdu_request, apdu_response); - send_Z_PDU(apdu_response); + send_Z_PDU(apdu_response, 0); } else { -- 1.7.10.4