Proxy with QOS support. XML config. Better logging
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 1 Oct 2003 13:13:51 +0000 (13:13 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 1 Oct 2003 13:13:51 +0000 (13:13 +0000)
23 files changed:
configure.in
include/yaz++/ir-assoc.h
include/yaz++/pdu-assoc.h
include/yaz++/pdu-observer.h
include/yaz++/proxy.h
include/yaz++/z-assoc.h
include/yaz++/z-query.h
include/yaz++/z-server.h
src/Makefile.am
src/yaz-bw.cpp [new file with mode: 0644]
src/yaz-ir-assoc.cpp
src/yaz-my-client.cpp
src/yaz-pdu-assoc.cpp
src/yaz-proxy-config.cpp [new file with mode: 0644]
src/yaz-proxy-main.cpp
src/yaz-proxy.cpp
src/yaz-z-assoc.cpp
src/yaz-z-cache.cpp
src/yaz-z-query.cpp
src/yaz-z-server-ill.cpp
src/yaz-z-server-sr.cpp
src/yaz-z-server-update.cpp
src/yaz-z-server.cpp

index a954fef..96b3dce 100644 (file)
@@ -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],
index 408f31f..aed30c6 100644 (file)
@@ -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 <yaz++/z-assoc.h>
@@ -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);
index e16c19f..fd217b4 100644 (file)
@@ -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 {
index 02b5fe8..d391189 100644 (file)
@@ -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.
index 54f93d3..dd86def 100644 (file)
@@ -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 <yaz++/z-assoc.h>
 #include <yaz++/z-query.h>
 #include <yaz++/z-databases.h>
 
+#if HAVE_XML2
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#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);
 };
 
index 02c7302..ada736b 100644 (file)
@@ -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
index ddc092d..57a2c44 100644 (file)
@@ -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 <yaz/proto.h>
@@ -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);
 };
index 7880575..df4acc8 100644 (file)
@@ -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 <yaz++/z-assoc.h>
@@ -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 ();
 
index ff0b7fb..a318b44 100644 (file)
@@ -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 (file)
index 0000000..73d69e4
--- /dev/null
@@ -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 <time.h>
+#include <yaz/log.h>
+#include <yaz++/proxy.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;
+}
+
index f8ca2d0..e0aaf7d 100644 (file)
@@ -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 <assert.h>
@@ -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);
 }
 
 
index 0df0b00..4ad8319 100644 (file)
@@ -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 <yaz/log.h>
index bcdeded..a7fc349 100644 (file)
@@ -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 <assert.h>
@@ -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 (file)
index 0000000..61cfb8d
--- /dev/null
@@ -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 <yaz/log.h>
+#include <yaz++/proxy.h>
+
+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)
+           {
+               // <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_target_info(ptr, url, keepalive,
+                                              limit_bw, limit_pdu, limit_req);
+                           return;
+                       }
+                   }
+           }
+           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,
+                                          "*")))
+                       {
+                           *url = name;
+                           return_target_info(ptr, url, keepalive,
+                                              limit_bw, limit_pdu, limit_req);
+                           return;
+                       }
+                   }
+           }
+       }
+    }
+#else
+    *url = name;
+    return;
+#endif
+}
+
+
index 9b7ffc5..a7faf3b 100644 (file)
@@ -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 <yaz/log.h>
@@ -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);
index ab518e7..81e987e 100644 (file)
  * 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 <assert.h>
 #include <time.h>
 
 #include <yaz/log.h>
+#include <yaz/diagbib1.h>
 #include <yaz++/proxy.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";
+}
+
+
 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; i<num; i++)
+    {
+       oident *ent;
+       Z_DefaultDiagFormat *r;
+        Z_DiagRec *p = pp[i];
+        if (p->which != 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)
     {
index 2761220..91b47ce 100644 (file)
@@ -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 <assert.h>
@@ -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;
 }
 
index 8571410..8e521e6 100644 (file)
@@ -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 <yaz/log.h>
@@ -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<num; i++)
     {
index 8e2fb3c..c0bed5e 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 1998-2001, Index Data.
+ * Copyright (c) 1998-2003, Index Data.
  * See the file LICENSE for details.
  * 
- * $Id: yaz-z-query.cpp,v 1.11 2002-10-09 12:50:26 adam Exp $
+ * $Id: yaz-z-query.cpp,v 1.12 2003-10-01 13:13:51 adam Exp $
  */
 
 #include <yaz++/z-query.h>
@@ -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; i<len; i++)
+    {
+       int ch = buf[i];
+       if (ch == '"')
+           wrbuf_putc(wbuf, '\\');
+       wrbuf_putc(wbuf, ch);
+    }
+    wrbuf_puts(wbuf, "\" ");
+}
+
+int Yaz_Z_Query::rpn2pquery(Z_RPNStructure *s, WRBUF buf)
+{
+    if (s->which == 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;
+}
+
+
index 3c42fb7..a9f23ce 100644 (file)
@@ -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 <yaz/log.h>
@@ -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;
 }
index cb0671b..680248a 100644 (file)
@@ -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;
index ddd30f8..ccfacf1 100644 (file)
@@ -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 <yaz/log.h>
@@ -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;
 }
index 10aba4d..dff2815 100644 (file)
@@ -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 <yaz/log.h>
@@ -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
     {