From: Adam Dickmeiss Date: Tue, 16 Dec 2003 14:17:00 +0000 (+0000) Subject: SRW/SRU protocol support. CQL->PQF map for Z39.50/SRW/SRU X-Git-Tag: YAZPP.0.7.4.larry~27 X-Git-Url: http://git.indexdata.com/?p=yazpp-moved-to-github.git;a=commitdiff_plain;h=307a8638d6429b0f77ad762d52309c550e45648c SRW/SRU protocol support. CQL->PQF map for Z39.50/SRW/SRU --- diff --git a/etc/config.xml b/etc/config.xml index 488b6d7..c4992b2 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -1,5 +1,5 @@ - + @@ -43,6 +43,7 @@ 2 + pqf.properties diff --git a/include/yaz++/ir-assoc.h b/include/yaz++/ir-assoc.h index aed30c6..a78f4b5 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.2 2003-10-01 13:13:51 adam Exp $ + * $Id: ir-assoc.h,v 1.3 2003-12-16 14:17:01 adam Exp $ */ #include @@ -20,6 +20,7 @@ class YAZ_EXPORT Yaz_IR_Assoc: public Yaz_Z_Assoc { virtual ~Yaz_IR_Assoc(); /// Receive Z39.50 PDU void recv_Z_PDU(Z_APDU *apdu, int len); + void recv_GDU(Z_GDU *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++/proxy.h b/include/yaz++/proxy.h index 33e4603..eed6ba0 100644 --- a/include/yaz++/proxy.h +++ b/include/yaz++/proxy.h @@ -2,13 +2,13 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: proxy.h,v 1.21 2003-10-23 11:45:08 adam Exp $ + * $Id: proxy.h,v 1.22 2003-12-16 14:17:01 adam Exp $ */ #include #include #include - +#include #if HAVE_XML2 #include #include @@ -42,7 +42,8 @@ public: int *max_clients, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init); + int *pre_init, + const char **cql2rpn); void get_generic_info(int *log_mask, int *max_clients); @@ -51,22 +52,23 @@ public: int *target_idletime, int *client_idletime, int *max_clients, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init); + int *pre_init, + const char **cql2rpn); int check_query(ODR odr, const char *name, Z_Query *query, char **addinfo); int check_syntax(ODR odr, const char *name, Odr_oid *syntax, char **addinfo); private: void operator=(const Yaz_ProxyConfig &conf); -#if HAVE_XML2 int mycmp(const char *hay, const char *item, size_t len); +#if HAVE_XML2 xmlDocPtr m_docPtr; xmlNodePtr m_proxyPtr; void return_target_info(xmlNodePtr ptr, const char **url, int *limit_bw, int *limit_pdu, int *limit_req, int *target_idletime, int *client_idletime, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init); + int *pre_init, const char **cql2rpn); void return_limit(xmlNodePtr ptr, int *limit_bw, int *limit_pdu, int *limit_req); int check_type_1(ODR odr, xmlNodePtr ptr, Z_RPNQuery *query, @@ -128,7 +130,9 @@ class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc { Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable, Yaz_Proxy *parent); ~Yaz_ProxyClient(); + void recv_GDU(Z_GDU *apdu, int len); void recv_Z_PDU(Z_APDU *apdu, int len); + void recv_HTTP_response(Z_HTTP_Response *apdu, int len); IYaz_PDU_Observer* sessionNotify (IYaz_PDU_Observable *the_PDU_Observable, int fd); void shutdown(); @@ -162,12 +166,24 @@ class YAZ_EXPORT Yaz_ProxyClient : public Yaz_Z_Assoc { Yaz_Proxy *m_root; }; +class YAZ_EXPORT Yaz_cql2rpn { + public: + Yaz_cql2rpn(); + ~Yaz_cql2rpn(); + void set_pqf_file(const char *fname); + int query_transform(const char *cql, Z_RPNQuery **rpnquery, ODR o); + private: + cql_transform_t m_transform; +}; + + /// Information Retrieval Proxy Server. class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { private: char *get_cookie(Z_OtherInformation **otherInfo); char *get_proxy(Z_OtherInformation **otherInfo); - Yaz_ProxyClient *get_client(Z_APDU *apdu); + Yaz_ProxyClient *get_client(Z_APDU *apdu, const char *cookie, + const char *proxy_host); Z_APDU *result_set_optimize(Z_APDU *apdu); void shutdown(); @@ -197,7 +213,7 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { Yaz_bw m_bw_stat; int m_pdu_max; Yaz_bw m_pdu_stat; - Z_APDU *m_bw_hold_PDU; + Z_GDU *m_bw_hold_PDU; int m_max_record_retrieve; void handle_max_record_retrieve(Z_APDU *apdu); void display_diagrecs(Z_DiagRec **pp, int num); @@ -205,6 +221,8 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { const char *addinfo); Z_APDU *handle_query_validation(Z_APDU *apdu); + Z_APDU *handle_query_transformation(Z_APDU *apdu); + Z_APDU *handle_syntax_validation(Z_APDU *apdu); const char *load_balance(const char **url); int m_reconfig_flag; @@ -213,12 +231,35 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { int m_invalid_session; int m_marcxml_flag; void convert_to_marcxml(Z_NamePlusRecordList *p); + Z_APDU *m_initRequest_apdu; + NMEM m_initRequest_mem; + Z_APDU *m_apdu_invalid_session; + NMEM m_mem_invalid_session; + int send_PDU_convert(Z_APDU *apdu, int *len); + ODR m_s2z_odr; + int m_s2z_hit_count; + int m_s2z_packing; + Z_APDU *m_s2z_init_apdu; + Z_APDU *m_s2z_search_apdu; + Z_APDU *m_s2z_present_apdu; + char *m_soap_ns; + int send_to_srw_client_error(int error); + int send_to_srw_client_ok(int hits, Z_Records *records); + int send_http_response(int code); + int send_srw_response(Z_SRW_PDU *srw_pdu); + + int z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res, + Z_DefaultDiagFormat *ddf); + int m_http_keepalive; + const char *m_http_version; + Yaz_cql2rpn m_cql2rpn; public: Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable, Yaz_Proxy *parent = 0); ~Yaz_Proxy(); - void recv_Z_PDU(Z_APDU *apdu, int len); - void recv_Z_PDU_0(Z_APDU *apdu); + void recv_GDU(Z_GDU *apdu, int len); + void handle_incoming_HTTP(Z_HTTP_Request *req); + void handle_incoming_Z_PDU(Z_APDU *apdu); IYaz_PDU_Observer* sessionNotify (IYaz_PDU_Observable *the_PDU_Observable, int fd); void failNotify(); @@ -239,5 +280,6 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { int server(const char *addr); void pre_init(); int get_log_mask() { return m_log_mask; }; + int handle_init_response_for_invalid_session(Z_APDU *apdu); }; diff --git a/include/yaz++/z-assoc.h b/include/yaz++/z-assoc.h index 49b8a68..c78906c 100644 --- a/include/yaz++/z-assoc.h +++ b/include/yaz++/z-assoc.h @@ -2,12 +2,13 @@ * Copyright (c) 1998-2000, Index Data. * See the file LICENSE for details. * - * $Id: z-assoc.h,v 1.5 2003-10-23 11:45:08 adam Exp $ + * $Id: z-assoc.h,v 1.6 2003-12-16 14:17:01 adam Exp $ */ #ifndef YAZ_Z_ASSOC_INCLUDED #define YAZ_Z_ASSOC_INCLUDED +#include #include #include #include @@ -39,13 +40,14 @@ class YAZ_EXPORT Yaz_Z_Assoc : public IYaz_PDU_Observer { /// Close connection void close(); /// Decode Z39.50 PDU. - Z_APDU *decode_Z_PDU(const char *buf, int len); + Z_GDU *decode_GDU(const char *buf, int len); /// Encode Z39.50 PDU. - int encode_Z_PDU(Z_APDU *apdu, char **buf, int *len); + int encode_GDU(Z_GDU *apdu, char **buf, int *len); /// Send Z39.50 PDU int send_Z_PDU(Z_APDU *apdu, int *len); + int send_GDU(Z_GDU *apdu, int *len); /// Receive Z39.50 PDU - virtual void recv_Z_PDU(Z_APDU *apdu, int len) = 0; + virtual void recv_GDU(Z_GDU *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-server.h b/include/yaz++/z-server.h index df4acc8..91731a9 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.3 2003-10-01 13:13:51 adam Exp $ + * $Id: z-server.h,v 1.4 2003-12-16 14:17:01 adam Exp $ */ #include @@ -119,7 +119,8 @@ 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, int len); + void recv_Z_PDU(Z_APDU *apdu, int len); + virtual void recv_GDU(Z_GDU *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 0d8e560..67f1bed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.19 2003-10-23 14:19:16 adam Exp $ +## $Id: Makefile.am,v 1.20 2003-12-16 14:17:01 adam Exp $ AM_CXXFLAGS = $(YAZINC) -I$(srcdir)/../include $(XML2_CFLAGS) @@ -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-proxy-config.cpp yaz-bw.cpp + yaz-z-cache.cpp yaz-proxy-config.cpp yaz-bw.cpp yaz-cql2rpn.cpp bin_PROGRAMS = yaz-proxy noinst_PROGRAMS = yaz-my-server yaz-my-client diff --git a/src/yaz-cql2rpn.cpp b/src/yaz-cql2rpn.cpp new file mode 100644 index 0000000..ec3fa54 --- /dev/null +++ b/src/yaz-cql2rpn.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1998-2003, Index Data. + * See the file LICENSE for details. + * + * $Id: yaz-cql2rpn.cpp,v 1.1 2003-12-16 14:17:01 adam Exp $ + */ + +#include +#include +#include + +Yaz_cql2rpn::Yaz_cql2rpn() +{ + m_transform = 0; +} + +Yaz_cql2rpn::~Yaz_cql2rpn() +{ + if (m_transform) + cql_transform_close(m_transform); +} + +void Yaz_cql2rpn::set_pqf_file(const char *fname) +{ + if (!m_transform) + m_transform = cql_transform_open_fname(fname); +} + +int Yaz_cql2rpn::query_transform(const char *cql_query, + Z_RPNQuery **rpnquery, ODR o) +{ + if (!m_transform) + return -3; + CQL_parser cp = cql_parser_create(); + + int r = cql_parser_string(cp, cql_query); + if (r) + { + yaz_log(LOG_LOG, "CQL Parse Error"); + return r; + } + else + { + char rpn_buf[1024]; + r = cql_transform_buf(m_transform, cql_parser_result(cp), + rpn_buf, sizeof(rpn_buf)-1); + if (!r) + { + YAZ_PQF_Parser pp = yaz_pqf_create(); + + *rpnquery = yaz_pqf_parse(pp, o, rpn_buf); + if (!*rpnquery) + { + size_t off; + const char *pqf_msg; + int code = yaz_pqf_error(pp, &pqf_msg, &off); + yaz_log(LOG_WARN, "PQF Parser Error %s (code %d)", + pqf_msg, code); + yaz_pqf_destroy(pp); + return -1; + } + yaz_pqf_destroy(pp); + } + else + { + const char *addinfo; + cql_transform_error(m_transform, &addinfo); + yaz_log(LOG_LOG, "CQL Transform Error %d %s", r, + addinfo ? addinfo : ""); + return -2; + } + } + return 0; +} diff --git a/src/yaz-ir-assoc.cpp b/src/yaz-ir-assoc.cpp index e0aaf7d..d5edf86 100644 --- a/src/yaz-ir-assoc.cpp +++ b/src/yaz-ir-assoc.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-ir-assoc.cpp,v 1.19 2003-10-01 13:13:51 adam Exp $ + * $Id: yaz-ir-assoc.cpp,v 1.20 2003-12-16 14:17:01 adam Exp $ */ #include @@ -149,6 +149,13 @@ void Yaz_IR_Assoc::get_elementSetName (const char **elementSetName) *elementSetName = m_elementSetNames->u.generic; } + +void Yaz_IR_Assoc::recv_GDU(Z_GDU *apdu, int len) +{ + if (apdu->which == Z_GDU_Z3950) + return recv_Z_PDU(apdu->u.z3950, len); +} + void Yaz_IR_Assoc::recv_Z_PDU(Z_APDU *apdu, int len) { yaz_log (m_log, "recv_Z_PDU %d bytes", len); diff --git a/src/yaz-proxy-config.cpp b/src/yaz-proxy-config.cpp index c4ed43d..6c3ffa6 100644 --- a/src/yaz-proxy-config.cpp +++ b/src/yaz-proxy-config.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-proxy-config.cpp,v 1.14 2003-11-25 21:54:18 adam Exp $ + * $Id: yaz-proxy-config.cpp,v 1.15 2003-12-16 14:17:01 adam Exp $ */ #include @@ -117,7 +117,8 @@ void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr, int *client_idletime, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init) + int *pre_init, + const char **cql2rpn) { *pre_init = 0; int no_url = 0; @@ -174,6 +175,13 @@ void Yaz_ProxyConfig::return_target_info(xmlNodePtr ptr, *client_idletime = 0; } } + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "cql2rpn")) + { + const char *t = get_text(ptr); + if (t) + *cql2rpn = t; + } } } #endif @@ -469,7 +477,8 @@ int Yaz_ProxyConfig::get_target_no(int no, int *max_clients, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init) + int *pre_init, + const char **cql2rpn) { #if HAVE_XML2 xmlNodePtr ptr; @@ -494,7 +503,7 @@ int Yaz_ProxyConfig::get_target_no(int no, return_target_info(ptr, url, limit_bw, limit_pdu, limit_req, target_idletime, client_idletime, keepalive_limit_bw, keepalive_limit_pdu, - pre_init); + pre_init, cql2rpn); return 1; } i++; @@ -572,7 +581,8 @@ void Yaz_ProxyConfig::get_target_info(const char *name, int *max_clients, int *keepalive_limit_bw, int *keepalive_limit_pdu, - int *pre_init) + int *pre_init, + const char **cql2rpn) { #if HAVE_XML2 xmlNodePtr ptr; @@ -608,7 +618,7 @@ void Yaz_ProxyConfig::get_target_info(const char *name, return_target_info(ptr, url, limit_bw, limit_pdu, limit_req, target_idletime, client_idletime, keepalive_limit_bw, keepalive_limit_pdu, - pre_init); + pre_init, cql2rpn); } #else *url = name; diff --git a/src/yaz-proxy.cpp b/src/yaz-proxy.cpp index 0dc0669..d623c36 100644 --- a/src/yaz-proxy.cpp +++ b/src/yaz-proxy.cpp @@ -2,17 +2,19 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-proxy.cpp,v 1.70 2003-11-08 18:51:10 adam Exp $ + * $Id: yaz-proxy.cpp,v 1.71 2003-12-16 14:17:01 adam Exp $ */ #include #include +#include #include #include #include #include #include +#include static const char *apdu_name(Z_APDU *apdu) { @@ -52,6 +54,20 @@ static const char *apdu_name(Z_APDU *apdu) return "other"; } +static const char *gdu_name(Z_GDU *gdu) +{ + switch(gdu->which) + { + case Z_GDU_Z3950: + return apdu_name(gdu->u.z3950); + case Z_GDU_HTTP_Request: + return "HTTP Request"; + case Z_GDU_HTTP_Response: + return "HTTP Response"; + } + return "Unknown request/response"; +} + Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable, Yaz_Proxy *parent) : Yaz_Z_Assoc(the_PDU_Observable), m_bw_stat(60), m_pdu_stat(60) @@ -85,16 +101,32 @@ Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable, m_invalid_session = 0; m_config = 0; m_marcxml_flag = 0; + m_initRequest_apdu = 0; + m_initRequest_mem = 0; + m_apdu_invalid_session = 0; + m_mem_invalid_session = 0; + m_s2z_odr = 0; + m_s2z_init_apdu = 0; + m_s2z_search_apdu = 0; + m_s2z_present_apdu = 0; + m_http_keepalive = 0; + m_http_version = 0; + m_soap_ns = 0; + m_s2z_packing = Z_SRW_recordPacking_string; } Yaz_Proxy::~Yaz_Proxy() { yaz_log(LOG_LOG, "%sClosed %d/%d sent/recv bytes total", m_session_str, m_bytes_sent, m_bytes_recv); + nmem_destroy(m_initRequest_mem); + nmem_destroy(m_mem_invalid_session); xfree (m_proxyTarget); xfree (m_default_target); xfree (m_proxy_authentication); xfree (m_optimize); + if (m_s2z_odr) + odr_destroy(m_s2z_odr); delete m_config; } @@ -241,24 +273,21 @@ const char *Yaz_Proxy::load_balance(const char **url) return ret; } -Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) +Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu, const char *cookie, + const char *proxy_host) { assert (m_parent); Yaz_Proxy *parent = m_parent; Z_OtherInformation **oi; Yaz_ProxyClient *c = m_client; - get_otherInfoAPDU(apdu, &oi); - char *cookie = get_cookie(oi); - if (!m_proxyTarget) { const char *url[MAX_ZURL_PLEX]; - const char *proxy_host = get_proxy(oi); Yaz_ProxyConfig *cfg = check_reconfigure(); if (proxy_host) { -#if 0 +#if 1 /* only to be enabled for debugging... */ if (!strcmp(proxy_host, "stop")) exit(0); @@ -268,6 +297,7 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) proxy_host = m_default_target; } int client_idletime = -1; + const char *cql2rpn_fname = 0; url[0] = m_default_target; url[1] = 0; if (cfg) @@ -279,13 +309,19 @@ Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu) &parent->m_max_clients, &m_keepalive_limit_bw, &m_keepalive_limit_pdu, - &pre_init); + &pre_init, + &cql2rpn_fname); } if (client_idletime != -1) { m_client_idletime = client_idletime; timeout(m_client_idletime); } + if (cql2rpn_fname) + { + yaz_log(LOG_LOG, "set_pqf_file %s", cql2rpn_fname); + m_cql2rpn.set_pqf_file(cql2rpn_fname); + } if (!url[0]) { yaz_log(LOG_LOG, "%sNo default target", m_session_str); @@ -595,9 +631,192 @@ void Yaz_Proxy::convert_to_marcxml(Z_NamePlusRecordList *p) yaz_marc_destroy(mt); } +int Yaz_Proxy::send_http_response(int code) +{ + ODR o = odr_encode(); + const char *ctype = "text/xml"; + Z_GDU *gdu = z_get_HTTP_Response(o, code); + Z_HTTP_Response *hres = gdu->u.HTTP_Response; + if (m_http_version) + hres->version = odr_strdup(o, m_http_version); + int len; + int r = send_GDU(gdu, &len); + delete this; + return r; +} + +int Yaz_Proxy::send_srw_response(Z_SRW_PDU *srw_pdu) +{ + ODR o = odr_encode(); + const char *ctype = "text/xml"; + Z_GDU *gdu = z_get_HTTP_Response(o, 200); + Z_HTTP_Response *hres = gdu->u.HTTP_Response; + if (m_http_version) + hres->version = odr_strdup(o, m_http_version); + z_HTTP_header_add(o, &hres->headers, "Content-Type", ctype); + if (m_http_keepalive) + z_HTTP_header_add(o, &hres->headers, "Connection", "Keep-Alive"); + + static Z_SOAP_Handler soap_handlers[2] = { +#if HAVE_XML2 + {"http://www.loc.gov/zing/srw/v1.0/", 0, + (Z_SOAP_fun) yaz_srw_codec}, +#endif + {0, 0, 0} + }; + + Z_SOAP *soap_package = (Z_SOAP*) odr_malloc(o, sizeof(Z_SOAP)); + soap_package->which = Z_SOAP_generic; + soap_package->u.generic = + (Z_SOAP_Generic *) odr_malloc(o, sizeof(*soap_package->u.generic)); + soap_package->u.generic->no = 0; + soap_package->u.generic->ns = soap_handlers[0].ns; + soap_package->u.generic->p = (void *) srw_pdu; + soap_package->ns = m_soap_ns; + int ret = z_soap_codec_enc(o, &soap_package, + &hres->content_buf, &hres->content_len, + soap_handlers, 0); + int len; + int r = send_GDU(gdu, &len); + if (!m_http_keepalive) + delete this; +} + +int Yaz_Proxy::send_to_srw_client_error(int srw_error) +{ + ODR o = odr_encode(); + Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response); + Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response; + + srw_res->num_diagnostics = 1; + srw_res->diagnostics = (Z_SRW_diagnostic *) + odr_malloc(o, sizeof(*srw_res->diagnostics)); + srw_res->diagnostics[0].code = odr_intdup(o, srw_error); + srw_res->diagnostics[0].details = 0; + return send_srw_response(srw_pdu); +} + +int Yaz_Proxy::z_to_srw_diag(ODR o, Z_SRW_searchRetrieveResponse *srw_res, + Z_DefaultDiagFormat *ddf) +{ + int bib1_code = *ddf->condition; + if (bib1_code == 109) + return 404; + srw_res->num_diagnostics = 1; + srw_res->diagnostics = (Z_SRW_diagnostic *) + odr_malloc(o, sizeof(*srw_res->diagnostics)); + srw_res->diagnostics[0].code = + odr_intdup(o, yaz_diag_bib1_to_srw(*ddf->condition)); + srw_res->diagnostics[0].details = ddf->u.v2Addinfo; + return 0; +} + +int Yaz_Proxy::send_to_srw_client_ok(int hits, Z_Records *records) +{ + ODR o = odr_encode(); + Z_SRW_PDU *srw_pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response); + Z_SRW_searchRetrieveResponse *srw_res = srw_pdu->u.response; + + srw_res->numberOfRecords = odr_intdup (o, hits); + if (records && records->which == Z_Records_DBOSD) + { + srw_res->num_records = + records->u.databaseOrSurDiagnostics->num_records; + int i; + srw_res->records = (Z_SRW_record *) + odr_malloc(o, srw_res->num_records * sizeof(Z_SRW_record)); + for (i = 0; i < srw_res->num_records; i++) + { + Z_NamePlusRecord *npr = records->u.databaseOrSurDiagnostics->records[i]; + if (npr->which != Z_NamePlusRecord_databaseRecord) + { + srw_res->records[i].recordSchema = "diagnostic"; + srw_res->records[i].recordPacking = m_s2z_packing; + srw_res->records[i].recordData_buf = "67"; + srw_res->records[i].recordData_len = 2; + srw_res->records[i].recordPosition = 0; + continue; + } + Z_External *r = npr->u.databaseRecord; + oident *ent = oid_getentbyoid(r->direct_reference); + if (r->which == Z_External_octet && ent->value == VAL_TEXT_XML) + { + srw_res->records[i].recordSchema = "http://www.loc.gov/marcxml/"; + srw_res->records[i].recordPacking = m_s2z_packing; + srw_res->records[i].recordData_buf = (char*) + r->u.octet_aligned->buf; + srw_res->records[i].recordData_len = r->u.octet_aligned->len; + srw_res->records[i].recordPosition = 0; + } + else + { + srw_res->records[i].recordSchema = "diagnostic"; + srw_res->records[i].recordPacking = m_s2z_packing; + srw_res->records[i].recordData_buf = "67"; + srw_res->records[i].recordData_len = 2; + srw_res->records[i].recordPosition = 0; + } + } + } + if (records && records->which == Z_Records_NSD) + { + int http_code; + http_code = z_to_srw_diag(odr_encode(), srw_res, + records->u.nonSurrogateDiagnostic); + if (http_code) + return send_http_response(http_code); + } + return send_srw_response(srw_pdu); + +} +int Yaz_Proxy::send_PDU_convert(Z_APDU *apdu, int *len) +{ + if (m_s2z_init_apdu && apdu->which == Z_APDU_initResponse) + { + m_s2z_init_apdu = 0; + Z_InitResponse *res = apdu->u.initResponse; + if (*res->result == 0) + { + send_to_srw_client_error(3); + } + else + { + handle_incoming_Z_PDU(m_s2z_search_apdu); + } + } + else if (m_s2z_search_apdu && apdu->which == Z_APDU_searchResponse) + { + m_s2z_search_apdu = 0; + Z_SearchResponse *res = apdu->u.searchResponse; + m_s2z_hit_count = *res->resultCount; + if (res->records && res->records->which == Z_Records_NSD) + { + send_to_srw_client_ok(0, res->records); + } + else if (m_s2z_present_apdu) + { + handle_incoming_Z_PDU(m_s2z_present_apdu); + } + else + { + send_to_srw_client_ok(m_s2z_hit_count, res->records); + } + } + else if (m_s2z_present_apdu && apdu->which == Z_APDU_presentResponse) + { + m_s2z_present_apdu = 0; + Z_PresentResponse *res = apdu->u.presentResponse; + send_to_srw_client_ok(m_s2z_hit_count, res->records); + } + else + return send_Z_PDU(apdu, len); + return 0; +} + int Yaz_Proxy::send_to_client(Z_APDU *apdu) { int len = 0; + int kill_session = 0; if (apdu->which == Z_APDU_searchResponse) { Z_SearchResponse *sr = apdu->u.searchResponse; @@ -608,6 +827,7 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu) dr.which = Z_DiagRec_defaultFormat; dr.u.defaultFormat = p->u.nonSurrogateDiagnostic; + *sr->searchStatus = 0; display_diagrecs(&dr_p, 1); } else @@ -619,7 +839,15 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu) yaz_log(LOG_LOG, "%s%d hits", m_session_str, *sr->resultCount); if (*sr->resultCount < 0) + { m_invalid_session = 1; + kill_session = 1; + + *sr->searchStatus = 0; + sr->records = + create_nonSurrogateDiagnostics(odr_encode(), 2, 0); + *sr->resultCount = 0; + } } } } @@ -632,18 +860,27 @@ int Yaz_Proxy::send_to_client(Z_APDU *apdu) Z_DiagRec dr, *dr_p = &dr; dr.which = Z_DiagRec_defaultFormat; dr.u.defaultFormat = p->u.nonSurrogateDiagnostic; - + if (*sr->presentStatus == Z_PresentStatus_success) + *sr->presentStatus = Z_PresentStatus_failure; display_diagrecs(&dr_p, 1); } if (m_marcxml_flag && p && p->which == Z_Records_DBOSD) convert_to_marcxml(p->u.databaseOrSurDiagnostics); } - int r = send_Z_PDU(apdu, &len); + int r = send_PDU_convert(apdu, &len); + if (r) + return r; if (m_log_mask & PROXY_LOG_APDU_CLIENT) yaz_log (LOG_DEBUG, "%sSending %s to client %d bytes", m_session_str, apdu_name(apdu), len); m_bytes_sent += len; m_bw_stat.add_bytes(len); + if (kill_session) + { + delete m_client; + m_client = 0; + m_parent->pre_init(); + } return r; } @@ -682,7 +919,6 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) send_to_client(new_apdu); return 0; } -#if 0 if (!strcmp(m_client->m_last_resultSetId, pr->resultSetId)) { if (start+toget-1 > m_client->m_last_resultCount) @@ -693,6 +929,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) send_to_client(new_apdu); return 0; } + Z_NamePlusRecordList *npr; if (m_client->m_cache.lookup (odr_encode(), &npr, start, toget, pr->preferredRecordSyntax, pr->recordComposition)) @@ -716,7 +953,6 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) return 0; } } -#endif } if (apdu->which != Z_APDU_searchRequest) @@ -888,7 +1124,7 @@ Z_APDU *Yaz_Proxy::result_set_optimize(Z_APDU *apdu) } -void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu, int len) +void Yaz_Proxy::recv_GDU(Z_GDU *apdu, int len) { char *cp = strchr(m_session_str, ' '); m_request_no++; @@ -899,7 +1135,7 @@ void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu, int len) if (m_log_mask & PROXY_LOG_APDU_CLIENT) yaz_log (LOG_DEBUG, "%sReceiving %s from client %d bytes", - m_session_str, apdu_name(apdu), len); + m_session_str, gdu_name(apdu), len); if (m_bw_hold_PDU) // double incoming PDU. shutdown now. shutdown(); @@ -934,8 +1170,10 @@ void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu, int len) 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 + else if (apdu->which == Z_GDU_Z3950) + handle_incoming_Z_PDU(apdu->u.z3950); + else if (apdu->which == Z_GDU_HTTP_Request) + handle_incoming_HTTP(apdu->u.HTTP_Request); } void Yaz_Proxy::handle_max_record_retrieve(Z_APDU *apdu) @@ -975,6 +1213,35 @@ Z_Records *Yaz_Proxy::create_nonSurrogateDiagnostics(ODR odr, return rec; } +Z_APDU *Yaz_Proxy::handle_query_transformation(Z_APDU *apdu) +{ + if (apdu->which == Z_APDU_searchRequest && + apdu->u.searchRequest->query && + apdu->u.searchRequest->query->which == Z_Query_type_104 && + apdu->u.searchRequest->query->u.type_104->which == Z_External_CQL) + { + Z_RPNQuery *rpnquery = 0; + Z_SearchRequest *sr = apdu->u.searchRequest; + + yaz_log(LOG_LOG, "%sCQL: %s", m_session_str, + sr->query->u.type_104->u.cql); + + int r = m_cql2rpn.query_transform(sr->query->u.type_104->u.cql, + &rpnquery, odr_encode()); + if (r == -3) + yaz_log(LOG_LOG, "%sNo CQL to RPN table", m_session_str); + else if (r) + yaz_log(LOG_LOG, "%sCQL Conversion error %d", m_session_str, r); + else + { + sr->query->which = Z_Query_type_1; + sr->query->u.type_1 = rpnquery; + } + return apdu; + } + return apdu; +} + Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu) { if (apdu->which == Z_APDU_searchRequest) @@ -1076,10 +1343,388 @@ Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu) return apdu; } -void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu) +static int hex_digit (int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a'+10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A'+10; + return 0; +} + +static char *uri_val(const char *path, const char *name, ODR o) +{ + size_t nlen = strlen(name); + if (*path != '?') + return 0; + path++; + while (path && *path) + { + const char *p1 = strchr(path, '='); + if (!p1) + break; + if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen)) + { + size_t i = 0; + char *ret; + + path = p1 + 1; + p1 = strchr(path, '&'); + if (!p1) + p1 = strlen(path) + path; + ret = (char*) odr_malloc(o, p1 - path + 1); + while (*path && *path != '&') + { + if (*path == '+') + { + ret[i++] = ' '; + path++; + } + else if (*path == '%' && path[1] && path[2]) + { + ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]); + path = path + 3; + } + else + ret[i++] = *path++; + } + ret[i] = '\0'; + return ret; + } + path = strchr(p1, '&'); + if (path) + path++; + } + return 0; +} + +void uri_val_int(const char *path, const char *name, ODR o, int **intp) { + const char *v = uri_val(path, name, o); + if (v) + *intp = odr_intdup(o, atoi(v)); +} + +int yaz_check_for_sru(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu, + char **soap_ns, ODR decode) +{ + if (!strcmp(hreq->method, "GET")) + { + char *db = "Default"; + const char *p0 = hreq->path, *p1; +#if HAVE_XML2 + int ret = -1; + char *charset = 0; + Z_SOAP *soap_package = 0; + static Z_SOAP_Handler soap_handlers[2] = { + {"http://www.loc.gov/zing/srw/v1.0/", 0, + (Z_SOAP_fun) yaz_srw_codec}, + {0, 0, 0} + }; +#endif + + if (*p0 == '/') + p0++; + p1 = strchr(p0, '?'); + if (!p1) + p1 = p0 + strlen(p0); + if (p1 != p0) + { + db = (char*) odr_malloc(decode, p1 - p0 + 1); + memcpy (db, p0, p1 - p0); + db[p1 - p0] = '\0'; + } +#if HAVE_XML2 + if (p1 && *p1 == '?' && p1[1]) + { + Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request); + char *query = uri_val(p1, "query", decode); + char *pQuery = uri_val(p1, "pQuery", decode); + char *sortKeys = uri_val(p1, "sortKeys", decode); + + *srw_pdu = sr; + if (query) + { + sr->u.request->query_type = Z_SRW_query_type_cql; + sr->u.request->query.cql = query; + } + if (pQuery) + { + sr->u.request->query_type = Z_SRW_query_type_pqf; + sr->u.request->query.pqf = pQuery; + } + if (sortKeys) + { + sr->u.request->sort_type = Z_SRW_sort_type_sort; + sr->u.request->sort.sortKeys = sortKeys; + } + sr->u.request->recordSchema = uri_val(p1, "recordSchema", decode); + sr->u.request->recordPacking = uri_val(p1, "recordPacking", decode); + if (!sr->u.request->recordPacking) + sr->u.request->recordPacking = "xml"; + uri_val_int(p1, "maximumRecords", decode, + &sr->u.request->maximumRecords); + uri_val_int(p1, "startRecord", decode, + &sr->u.request->startRecord); + if (sr->u.request->startRecord) + yaz_log(LOG_LOG, "startRecord=%d", *sr->u.request->startRecord); + sr->u.request->database = db; + *soap_ns = "SRU"; + return 0; + } +#endif + return 1; + } + return 2; +} + +int yaz_check_for_srw(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu, + char **soap_ns, ODR decode) +{ + if (!strcmp(hreq->method, "POST")) + { + const char *content_type = z_HTTP_header_lookup(hreq->headers, + "Content-Type"); + if (content_type && !yaz_strcmp_del("text/xml", content_type, "; ")) + { + char *db = "Default"; + const char *p0 = hreq->path, *p1; + Z_SOAP *soap_package = 0; + int ret = -1; + int http_code = 500; + const char *charset_p = 0; + char *charset = 0; + + static Z_SOAP_Handler soap_handlers[2] = { +#if HAVE_XML2 + {"http://www.loc.gov/zing/srw/v1.0/", 0, + (Z_SOAP_fun) yaz_srw_codec}, +#endif + {0, 0, 0} + }; + + if (*p0 == '/') + p0++; + p1 = strchr(p0, '?'); + if (!p1) + p1 = p0 + strlen(p0); + if (p1 != p0) + { + db = (char*) odr_malloc(decode, p1 - p0 + 1); + memcpy (db, p0, p1 - p0); + db[p1 - p0] = '\0'; + } + + if ((charset_p = strstr(content_type, "; charset="))) + { + int i = 0; + charset_p += 10; + while (i < 20 && charset_p[i] && + !strchr("; \n\r", charset_p[i])) + i++; + charset = (char*) odr_malloc(decode, i+1); + memcpy(charset, charset_p, i); + charset[i] = '\0'; + yaz_log(LOG_LOG, "SOAP encoding %s", charset); + } + ret = z_soap_codec(decode, &soap_package, + &hreq->content_buf, &hreq->content_len, + soap_handlers); + if (!ret && soap_package->which == Z_SOAP_generic && + soap_package->u.generic->no == 0) + { + *srw_pdu = (Z_SRW_PDU*) soap_package->u.generic->p; + + if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request && + (*srw_pdu)->u.request->database == 0) + (*srw_pdu)->u.request->database = db; + + *soap_ns = odr_strdup(decode, soap_package->ns); + return 0; + } + return 1; + } + } + return 2; +} + +void Yaz_Proxy::handle_incoming_HTTP(Z_HTTP_Request *hreq) +{ + Z_SRW_PDU *srw_pdu = 0; + char *soap_ns = 0; + if (m_s2z_odr) + { + odr_destroy(m_s2z_odr); + m_s2z_odr = 0; + } + + m_http_keepalive = 0; + m_http_version = 0; + if (!strcmp(hreq->version, "1.0")) + { + const char *v = z_HTTP_header_lookup(hreq->headers, "Connection"); + if (v && !strcmp(v, "Keep-Alive")) + m_http_keepalive = 1; + else + m_http_keepalive = 0; + m_http_version = "1.0"; + } + else + { + const char *v = z_HTTP_header_lookup(hreq->headers, "Connection"); + if (v && !strcmp(v, "close")) + m_http_keepalive = 0; + else + m_http_keepalive = 1; + m_http_version = "1.1"; + } + + if (yaz_check_for_srw(hreq, &srw_pdu, &soap_ns, odr_decode()) == 0 + || yaz_check_for_sru(hreq, &srw_pdu, &soap_ns, odr_decode()) == 0) + { + m_s2z_odr = odr_createmem(ODR_ENCODE); + m_soap_ns = odr_strdup(m_s2z_odr, soap_ns); + m_s2z_init_apdu = 0; + m_s2z_search_apdu = 0; + m_s2z_present_apdu = 0; + if (srw_pdu->which == Z_SRW_searchRetrieve_request) + { + Z_SRW_searchRetrieveRequest *srw_req = srw_pdu->u.request; + + // set packing for response records .. + if (srw_req->recordPacking && + !strcmp(srw_req->recordPacking, "xml")) + m_s2z_packing = Z_SRW_recordPacking_XML; + else + m_s2z_packing = Z_SRW_recordPacking_string; + + // prepare search PDU + m_s2z_search_apdu = zget_APDU(m_s2z_odr, Z_APDU_searchRequest); + Z_SearchRequest *z_searchRequest = + m_s2z_search_apdu->u.searchRequest; + + z_searchRequest->num_databaseNames = 1; + z_searchRequest->databaseNames = (char**) + odr_malloc(m_s2z_odr, sizeof(char *)); + z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr, + srw_req->database); + + // query transformation + Z_Query *query = (Z_Query *) + odr_malloc(odr_encode(), sizeof(Z_Query)); + z_searchRequest->query = query; + + if (srw_req->query_type == Z_SRW_query_type_cql) + { + Z_External *ext = (Z_External *) + odr_malloc(m_s2z_odr, sizeof(*ext)); + ext->direct_reference = + odr_getoidbystr(m_s2z_odr, "1.2.840.10003.16.2"); + ext->indirect_reference = 0; + ext->descriptor = 0; + ext->which = Z_External_CQL; + ext->u.cql = srw_req->query.cql; + + query->which = Z_Query_type_104; + query->u.type_104 = ext; + } + else if (srw_req->query_type == Z_SRW_query_type_pqf) + { + Z_RPNQuery *RPNquery; + YAZ_PQF_Parser pqf_parser; + + pqf_parser = yaz_pqf_create (); + + RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr, + srw_req->query.pqf); + if (!RPNquery) + { + const char *pqf_msg; + size_t off; + int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off); + yaz_log(LOG_LOG, "%*s^\n", off+4, ""); + yaz_log(LOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code); + + send_to_srw_client_error(10); + return; + } + query->which = Z_Query_type_1; + query->u.type_1 = RPNquery; + + yaz_pqf_destroy (pqf_parser); + } + else + { + send_to_srw_client_error(11); + return; + } + + // present + m_s2z_present_apdu = 0; + int max = 0; + if (srw_req->maximumRecords) + max = *srw_req->maximumRecords; + int start = 1; + if (srw_req->startRecord) + start = *srw_req->startRecord; + if (max > 0) + { + if (start <= 1) // Z39.50 piggyback + { + *z_searchRequest->smallSetUpperBound = max; + *z_searchRequest->mediumSetPresentNumber = max; + *z_searchRequest->largeSetLowerBound = 2000000000; // 2e9 + z_searchRequest->preferredRecordSyntax = + yaz_oidval_to_z3950oid(m_s2z_odr, CLASS_RECSYN, + VAL_TEXT_XML); + } + else // Z39.50 present + { + m_s2z_present_apdu = zget_APDU(m_s2z_odr, + Z_APDU_presentRequest); + Z_PresentRequest *z_presentRequest = + m_s2z_present_apdu->u.presentRequest; + *z_presentRequest->resultSetStartPoint = start; + *z_presentRequest->numberOfRecordsRequested = max; + z_presentRequest->preferredRecordSyntax = + yaz_oidval_to_z3950oid(m_s2z_odr, CLASS_RECSYN, + VAL_TEXT_XML); + } + } + if (!m_client) + { + m_s2z_init_apdu = zget_APDU(m_s2z_odr, Z_APDU_initRequest); + handle_incoming_Z_PDU(m_s2z_init_apdu); + return; + } + else + { + handle_incoming_Z_PDU(m_s2z_search_apdu); + return; + } + } + } + int len = 0; + Z_GDU *p = z_get_HTTP_Response(odr_encode(), 400); + send_GDU(p, &len); + timeout(1); +} + +void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu) +{ + if (!m_client && m_invalid_session) + { + m_apdu_invalid_session = apdu; + m_mem_invalid_session = odr_extract_mem(odr_decode()); + apdu = m_initRequest_apdu; + } + // Determine our client. - m_client = get_client(apdu); + Z_OtherInformation **oi; + get_otherInfoAPDU(apdu, &oi); + m_client = get_client(apdu, get_cookie(oi), get_proxy(oi)); if (!m_client) { delete this; @@ -1098,8 +1743,17 @@ void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu) if (apdu->u.initRequest->implementationVersion) yaz_log(LOG_LOG, "%simplementationVersion: %s", m_session_str, apdu->u.initRequest->implementationVersion); + if (m_initRequest_apdu == 0) + { + if (m_initRequest_mem) + nmem_destroy(m_initRequest_mem); + m_initRequest_apdu = apdu; + m_initRequest_mem = odr_extract_mem(odr_decode()); + } if (m_client->m_init_flag) { + if (handle_init_response_for_invalid_session(apdu)) + return; Z_APDU *apdu = m_client->m_initResponse; apdu->u.initResponse->otherInfo = 0; if (m_client->m_cookie && *m_client->m_cookie) @@ -1116,6 +1770,9 @@ void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu) apdu = handle_syntax_validation(apdu); if (apdu) + apdu = handle_query_transformation(apdu); + + if (apdu) apdu = handle_query_validation(apdu); if (apdu) @@ -1128,7 +1785,6 @@ void Yaz_Proxy::recv_Z_PDU_0(Z_APDU *apdu) } // delete other info part from PDU before sending to target - Z_OtherInformation **oi; get_otherInfoAPDU(apdu, &oi); if (oi) *oi = 0; @@ -1158,9 +1814,9 @@ void Yaz_Proxy::connectNotify() void Yaz_Proxy::shutdown() { + m_invalid_session = 0; // only keep if keep_alive flag is set... if (m_client && - !m_invalid_session && m_client->m_pdu_recv < m_keepalive_limit_pdu && m_client->m_bytes_recv+m_client->m_bytes_sent < m_keepalive_limit_bw && m_client->m_waiting == 0) @@ -1175,6 +1831,7 @@ void Yaz_Proxy::shutdown() assert (m_client->m_waiting != 2); // Tell client (if any) that no server connection is there.. m_client->m_server = 0; + m_invalid_session = 0; } else if (m_client) { @@ -1298,6 +1955,7 @@ void Yaz_Proxy::pre_init() int max_clients; int keepalive_limit_bw, keepalive_limit_pdu; int pre_init; + const char *cql2rpn = 0; Yaz_ProxyConfig *cfg = check_reconfigure(); @@ -1314,7 +1972,8 @@ void Yaz_Proxy::pre_init() &max_clients, &keepalive_limit_bw, &keepalive_limit_pdu, - &pre_init) ; i++) + &pre_init, + &cql2rpn) ; i++) { if (pre_init) { @@ -1380,9 +2039,13 @@ void Yaz_Proxy::timeoutNotify() if (m_bw_hold_PDU) { timeout(m_client_idletime); - Z_APDU *apdu = m_bw_hold_PDU; + Z_GDU *apdu = m_bw_hold_PDU; m_bw_hold_PDU = 0; - recv_Z_PDU_0(apdu); + + if (apdu->which == Z_GDU_Z3950) + handle_incoming_Z_PDU(apdu->u.z3950); + else if (apdu->which == Z_GDU_HTTP_Request) + handle_incoming_HTTP(apdu->u.HTTP_Request); } else { @@ -1443,6 +2106,33 @@ const char *Yaz_Proxy::option(const char *name, const char *value) return 0; } +void Yaz_ProxyClient::recv_HTTP_response(Z_HTTP_Response *apdu, int len) +{ + +} + +void Yaz_ProxyClient::recv_GDU(Z_GDU *apdu, int len) +{ + if (apdu->which == Z_GDU_Z3950) + recv_Z_PDU(apdu->u.z3950, len); + else if (apdu->which == Z_GDU_HTTP_Response) + recv_HTTP_response(apdu->u.HTTP_Response, len); + else + shutdown(); +} + +int Yaz_Proxy::handle_init_response_for_invalid_session(Z_APDU *apdu) +{ + if (!m_invalid_session) + return 0; + m_invalid_session = 0; + handle_incoming_Z_PDU(m_apdu_invalid_session); + assert (m_mem_invalid_session); + nmem_destroy(m_mem_invalid_session); + m_mem_invalid_session = 0; + return 1; +} + void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len) { m_bytes_recv += len; @@ -1475,6 +2165,9 @@ void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu, int len) ir->implementationName = im1; nmem_destroy (nmem); + + if (m_server && m_server->handle_init_response_for_invalid_session(apdu)) + return; } if (apdu->which == Z_APDU_searchResponse) { diff --git a/src/yaz-z-assoc.cpp b/src/yaz-z-assoc.cpp index b832572..72a3d41 100644 --- a/src/yaz-z-assoc.cpp +++ b/src/yaz-z-assoc.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-assoc.cpp,v 1.31 2003-10-23 13:49:58 adam Exp $ + * $Id: yaz-z-assoc.cpp,v 1.32 2003-12-16 14:17:01 adam Exp $ */ #include @@ -85,10 +85,10 @@ Yaz_Z_Assoc::~Yaz_Z_Assoc() void Yaz_Z_Assoc::recv_PDU(const char *buf, int len) { yaz_log (m_log, "recv_PDU len=%d", len); - Z_APDU *apdu = decode_Z_PDU (buf, len); + Z_GDU *apdu = decode_GDU (buf, len); if (apdu) { - recv_Z_PDU (apdu, len); + recv_GDU (apdu, len); } else { @@ -182,9 +182,17 @@ void Yaz_Z_Assoc::transfer_referenceId(Z_APDU *from, Z_APDU *to) int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu, int *plen) { + Z_GDU *gdu = (Z_GDU*) odr_malloc(odr_encode(), sizeof(*gdu)); + gdu->which = Z_GDU_Z3950; + gdu->u.z3950 = apdu; + return send_GDU(gdu, plen); +} + +int Yaz_Z_Assoc::send_GDU(Z_GDU *apdu, int *plen) +{ char *buf; int len; - if (encode_Z_PDU(apdu, &buf, &len) > 0) + if (encode_GDU(apdu, &buf, &len) > 0) { if (plen) *plen = len; @@ -193,14 +201,14 @@ int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu, int *plen) return -1; } -Z_APDU *Yaz_Z_Assoc::decode_Z_PDU(const char *buf, int len) +Z_GDU *Yaz_Z_Assoc::decode_GDU(const char *buf, int len) { - Z_APDU *apdu; + Z_GDU *apdu; odr_reset (m_odr_in); odr_setbuf (m_odr_in, (char*) buf, len, 0); - if (!z_APDU(m_odr_in, &apdu, 0, 0)) + if (!z_GDU(m_odr_in, &apdu, 0, 0)) { yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ", odr_errmsg(odr_geterror(m_odr_in)), @@ -216,39 +224,39 @@ Z_APDU *Yaz_Z_Assoc::decode_Z_PDU(const char *buf, int len) FILE *save = m_APDU_file; odr_setprint(m_odr_print, yaz_log_file()); - z_APDU(m_odr_print, &apdu, 0, "decode"); + z_GDU(m_odr_print, &apdu, 0, "decode"); m_APDU_file = save; odr_setprint(m_odr_print, save); } if (m_APDU_file) { - z_APDU(m_odr_print, &apdu, 0, "decode"); + z_GDU(m_odr_print, &apdu, 0, "decode"); fflush(m_APDU_file); } return apdu; } } -int Yaz_Z_Assoc::encode_Z_PDU(Z_APDU *apdu, char **buf, int *len) +int Yaz_Z_Assoc::encode_GDU(Z_GDU *apdu, char **buf, int *len) { if (m_APDU_yazlog) { FILE *save = m_APDU_file; odr_setprint(m_odr_print, yaz_log_file()); // use YAZ log FILE - z_APDU(m_odr_print, &apdu, 0, "encode"); + z_GDU(m_odr_print, &apdu, 0, "encode"); m_APDU_file = save; odr_setprint(m_odr_print, save); } if (m_APDU_file) { - z_APDU(m_odr_print, &apdu, 0, "encode"); + z_GDU(m_odr_print, &apdu, 0, "encode"); fflush(m_APDU_file); } - if (!z_APDU(m_odr_out, &apdu, 0, 0)) + if (!z_GDU(m_odr_out, &apdu, 0, 0)) { if (m_APDU_file) fprintf (m_APDU_file, "PDU encode failed (above)"); - yaz_log (LOG_LOG, "yaz_Z_Assoc::encode_Z_PDU failed"); + yaz_log (LOG_LOG, "yaz_Z_Assoc::encode_Z_GDU failed"); return -1; } *buf = odr_getbuf (m_odr_out, len, 0); diff --git a/src/yaz-z-query.cpp b/src/yaz-z-query.cpp index 8d391d5..1f178cc 100644 --- a/src/yaz-z-query.cpp +++ b/src/yaz-z-query.cpp @@ -2,7 +2,7 @@ * Copyright (c) 1998-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-query.cpp,v 1.13 2003-10-03 13:01:42 adam Exp $ + * $Id: yaz-z-query.cpp,v 1.14 2003-12-16 14:17:01 adam Exp $ */ #include @@ -78,9 +78,9 @@ void Yaz_Z_Query::print(char *str, int len) } else strcpy(str, wrbuf_buf(wbuf)); + wrbuf_free(wbuf,1); } odr_reset(odr_decode); - wrbuf_free(wbuf,1); } int Yaz_Z_Query::match(Yaz_Z_Query *other) diff --git a/src/yaz-z-server.cpp b/src/yaz-z-server.cpp index dff2815..99ef2db 100644 --- a/src/yaz-z-server.cpp +++ b/src/yaz-z-server.cpp @@ -2,7 +2,7 @@ * Copyright (c) 2000-2003, Index Data. * See the file LICENSE for details. * - * $Id: yaz-z-server.cpp,v 1.16 2003-10-01 13:13:51 adam Exp $ + * $Id: yaz-z-server.cpp,v 1.17 2003-12-16 14:17:01 adam Exp $ */ #include @@ -48,6 +48,14 @@ void Yaz_Z_Server::facility_add(IYaz_Server_Facility *facility, (*p)->m_facility = facility; } +void Yaz_Z_Server::recv_GDU (Z_GDU *apdu, int len) +{ + if (apdu->which == Z_GDU_Z3950) + return recv_Z_PDU(apdu->u.z3950, len); + else + delete this; +} + void Yaz_Z_Server::recv_Z_PDU (Z_APDU *apdu_request, int len) { Yaz_Z_Server_Facility_Info *f = m_facilities;