From: Adam Dickmeiss Date: Wed, 5 Oct 2005 12:07:14 +0000 (+0000) Subject: Initial checkin of proxy 2 code X-Git-Tag: YAZPROXY.1.1.0.2~46 X-Git-Url: http://git.indexdata.com/?p=yazproxy-moved-to-github.git;a=commitdiff_plain;h=42cd2c5dddd315dd85b626b125a750e8203c739a Initial checkin of proxy 2 code --- diff --git a/src/.cvsignore b/src/.cvsignore index 0fad00d..029305f 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -8,3 +8,4 @@ Makefile.in cdetails t-server tstthreads +p2 diff --git a/src/Makefile.am b/src/Makefile.am index 1747d6d..bd4a9b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.9 2005-06-21 21:54:05 adam Exp $ +## $Id: Makefile.am,v 1.10 2005-10-05 12:07:14 adam Exp $ AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC) @@ -11,7 +11,7 @@ libyazproxy_la_SOURCES= yaz-proxy.cpp yaz-proxy-config.cpp yaz-bw.cpp \ bin_PROGRAMS = yazproxy check_PROGRAMS = cdetails -noinst_PROGRAMS = tstthreads t-server +noinst_PROGRAMS = tstthreads t-server p2 TESTS=$(check_PROGRAMS) @@ -19,6 +19,11 @@ yazproxy_SOURCES=yaz-proxy-main.cpp cdetails_SOURCES=cdetails.cpp tstthreads_SOURCES=tstthreads.cpp t_server_SOURCES=t-server.cpp +p2_SOURCES=p2_frontend.cpp p2_msg.cpp p2.cpp p2_frontend.h \ + p2_config.cpp p2_config.h \ + p2_backend.h p2_backend_dummy.cpp \ + p2_modules.cpp p2_modules.h \ + p2_xmlerror.cpp p2_xmlerror.h LDADD=libyazproxy.la $(YAZPPLALIB) $(XSLT_LIBS) $(USEMARCONLALIB) libyazproxy_la_LIBADD = $(XSLT_LIBS) diff --git a/src/p2.cpp b/src/p2.cpp new file mode 100644 index 0000000..ee586d5 --- /dev/null +++ b/src/p2.cpp @@ -0,0 +1,146 @@ +/* $Id: p2.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include "p2_config.h" +#include "p2_frontend.h" +#include "p2_xmlerror.h" +#include "p2_modules.h" + +using namespace yazpp_1; + +extern P2_ModuleEntry *p2_backend_dummy; + +/* + frontend result set map + resultset -> db,query + + backend result set map + db,query -> resultset, target + resultset, target +*/ +class P2_Frontend; + +P2_Config *P2_Server::lockConfig() +{ + pthread_mutex_lock(&m_mutex_config); + return m_config; +} + +void P2_Server::unlockConfig() +{ + pthread_mutex_unlock(&m_mutex_config); +} + +P2_Server::P2_Server(IPDU_Observable *the_PDU_Observable, + Msg_Thread *my_thread, + P2_Config *config, + P2_ModuleFactory *modules) + : Z_Assoc(the_PDU_Observable) +{ + m_my_thread = my_thread; + m_modules = modules; + m_config = config; + + pthread_mutex_init(&m_mutex_config, 0); + + yaz_log(YLOG_LOG, "Construct P2_Server=%p", this); +} + +IPDU_Observer *P2_Server::sessionNotify(IPDU_Observable + *the_PDU_Observable, int fd) +{ + P2_Frontend *my = new P2_Frontend(the_PDU_Observable, m_my_thread, this); + yaz_log(YLOG_LOG, "New session %s", the_PDU_Observable->getpeername()); + return my; +} + +P2_Server::~P2_Server() +{ + yaz_log(YLOG_LOG, "Destroy P2_server=%p", this); + pthread_mutex_destroy(&m_mutex_config); +} + +void P2_Server::recv_GDU(Z_GDU *apdu, int len) +{ +} + +void P2_Server::failNotify() +{ +} + +void P2_Server::timeoutNotify() +{ +} + +void P2_Server::connectNotify() +{ +} + +int main(int argc, char **argv) +{ + p2_xmlerror_setup(); + + P2_Config config; + + if (!config.parse_options(argc, argv)) + { + yaz_log(YLOG_FATAL, "Configuration incorrect. Exiting"); + exit(1); + } + + SocketManager mySocketManager; + + PDU_Assoc *my_PDU_Assoc = 0; + + Msg_Thread my_thread(&mySocketManager, config.m_no_threads); + + my_PDU_Assoc = new PDU_Assoc(&mySocketManager); + + P2_ModuleFactory modules; + + modules.add(p2_backend_dummy); + + std::list::const_iterator it; + for (it = config.m_modules.begin(); it != config.m_modules.end(); it++) + modules.add((*it)->m_fname.c_str()); + + P2_Server z(my_PDU_Assoc, &my_thread, &config, &modules); + z.server(config.m_listen_address.c_str()); + + while (mySocketManager.processEvent() > 0) + ; + return 0; +} +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/p2_backend.h b/src/p2_backend.h new file mode 100644 index 0000000..b5864b3 --- /dev/null +++ b/src/p2_backend.h @@ -0,0 +1,31 @@ + +#ifndef P2_BACKEND_H +#define P2_BACKEND_H + +#include + +class IP2_BackendSet { +public: + virtual ~IP2_BackendSet(); + virtual int get(int start, int number) = 0; +}; + +class IP2_Backend { + public: + virtual ~IP2_Backend(); + virtual int search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset, int *hits) = 0; +}; + +struct P2_ModuleInterface0 { + IP2_Backend *(*create)(const char *address); +}; + +struct P2_ModuleEntry { + int version; + const char *name; + const char *description; + void *interface_ptr; +}; + + +#endif diff --git a/src/p2_backend_dummy.cpp b/src/p2_backend_dummy.cpp new file mode 100644 index 0000000..79e8490 --- /dev/null +++ b/src/p2_backend_dummy.cpp @@ -0,0 +1,74 @@ + +#include +#include "p2_backend.h" + +class P2_BackendSetDummy : public IP2_BackendSet { +public: + P2_BackendSetDummy(); + ~P2_BackendSetDummy(); + int get(int start, int number); +}; + +class P2_BackendDummy : public IP2_Backend { +public: + P2_BackendDummy(const char *address); + ~P2_BackendDummy(); + int search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset, int *hits); +}; + +P2_BackendDummy::P2_BackendDummy(const char *address) +{ + yaz_log(YLOG_LOG, "P2_backendDummy %p create", this); +} + +P2_BackendDummy::~P2_BackendDummy() +{ + yaz_log(YLOG_LOG, "P2_backendDummy %p destroy", this); +} + +int P2_BackendDummy::search(yazpp_1::Yaz_Z_Query *q, IP2_BackendSet **rset, + int *hits) +{ + yaz_log(YLOG_LOG, "P2_backendDummy %p search", this); + + P2_BackendSetDummy *s = new P2_BackendSetDummy(); + + *rset = s; + *hits = 42; + return 0; +} + +int P2_BackendSetDummy::get(int start, int number) +{ + yaz_log(YLOG_LOG, "P2_backendSetDummy %p get", this); + return 0; +} + +P2_BackendSetDummy::P2_BackendSetDummy() +{ + yaz_log(YLOG_LOG, "P2_backendSetDummy %p create", this); + +} + +P2_BackendSetDummy::~P2_BackendSetDummy() +{ + yaz_log(YLOG_LOG, "P2_backendSetDummy %p destroy", this); +} + +static IP2_Backend *dummy_create(const char *address) +{ + return new P2_BackendDummy(address); +} + +P2_ModuleInterface0 int0 = { + dummy_create +}; + +P2_ModuleEntry p2_module_entry = { + 0, + "dummy", + "Dummy Backend", + (void *) &int0 +}; + +P2_ModuleEntry *p2_backend_dummy = &p2_module_entry; diff --git a/src/p2_config.cpp b/src/p2_config.cpp new file mode 100644 index 0000000..de50049 --- /dev/null +++ b/src/p2_config.cpp @@ -0,0 +1,383 @@ +/* $Id: p2_config.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include "p2_config.h" + +#if HAVE_XSLT +#include +#include +#include +#include +#include +#endif + +#include + +using namespace std; + +class P2_Config::Rep { + +public: + Rep(); + ~Rep(); +public: +#if HAVE_XSLT + xmlDocPtr m_docPtr; + xmlNodePtr m_proxyPtr; +#endif +}; + +P2_Config::Rep::Rep() +{ +#if HAVE_XSLT + m_docPtr = 0; + m_proxyPtr = 0; +#endif +} + +P2_Config::Rep::~Rep() +{ +#if HAVE_XSLT + if (m_docPtr) + xmlFreeDoc(m_docPtr); +#endif +} + +P2_Config::P2_Config() +{ + m_max_clients = 500; + m_client_idletime = 600; + m_debug_mode = 0; + m_no_limit_files = 0; + m_no_threads = 20; + m_target_idletime = 600; + + m_rep = new Rep(); +} + +bool P2_Config::parse_options(int argc, char **argv) +{ + char *arg; + int ret; + bool show_config = false; + while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:n:h:XS", + argv, argc, &arg)) != -2) + { + switch (ret) + { + case 0: + if (m_listen_address.length()) + { + yaz_log(YLOG_FATAL, "Multiple listener address given"); + return false; + } + m_listen_address = arg; + break; + case 'a': + m_apdu_log = arg; + break; + case 'c': + if (m_xml_fname.length()) + { + yaz_log(YLOG_FATAL, "Multiple -c options given"); + return false; + } + if (!read_xml_config(arg)) + { + return false; + } + m_xml_fname = arg; + break; + case 'i': + m_client_idletime = atoi(arg); + break; + case 'l': + m_log_file = arg; + break; + case 'm': + m_max_clients = atoi(arg); + break; + case 'n': + m_no_limit_files = atoi(arg); + break; + case 'h': + m_no_threads = atoi(arg); + break; + case 'o': + m_optimize_flags = arg; + break; + case 'p': + if (m_pid_fname.length()) + { + yaz_log(YLOG_LOG, "Multiple -p options given"); + return false; + } + m_pid_fname = arg; + break; + case 't': + if (m_default_target.length()) + { + yaz_log(YLOG_LOG, "Multiple -t options given"); + return false; + } + m_default_target = arg; + break; + case 'T': + m_target_idletime = atoi(arg); + break; + case 'u': + if (m_uid.length()) + { + yaz_log(YLOG_FATAL, "-u specified more than once"); + return false; + } + m_uid = arg; + break; + case 'v': + yaz_log_init_level(yaz_log_mask_str(arg)); + break; + case 'X': + m_debug_mode = 1; + break; + case 'S': + show_config = true; + break; + default: + yaz_log(YLOG_FATAL, "Bad option %s", arg); + return false; + } + } + if (m_log_file.length()) + yaz_log_init_file(m_log_file.c_str()); + if (show_config) + print(); + return true; +} + +bool P2_Config::parse_xml_text(void *xml_ptr, bool &val) +{ + string v; + if (!parse_xml_text(xml_ptr, v)) + return false; + if (v.length() == 1 && v[0] == '1') + val = true; + else + val = false; + return true; +} + +bool P2_Config::parse_xml_text(void *xml_ptr, string &val) +{ + xmlNodePtr ptr = (xmlNodePtr) xml_ptr; + bool found = false; + string v; + for(ptr = ptr->children; ptr; ptr = ptr->next) + if (ptr->type == XML_TEXT_NODE) + { + xmlChar *t = ptr->content; + if (t) + { + v += (const char *) t; + found = true; + } + } + if (found) + val = v; + return found; +} + +void P2_Config::parse_xml_element_target(void *xml_ptr, + P2_ConfigTarget *t) +{ + xmlNodePtr ptr = (xmlNodePtr) xml_ptr; + + for (ptr = ptr->children; ptr; ptr = ptr->next) + { + if (ptr->type != XML_ELEMENT_NODE) + continue; + if (!strcmp((const char *) ptr->name, "url")) + { + parse_xml_text(ptr, t->m_target_address); + } + else if (!strcmp((const char *) ptr->name, "database")) + { + parse_xml_text(ptr, t->m_target_database); + } + else + { + yaz_log(YLOG_WARN, "Unknown element '%s' inside target", + (const char *) ptr->name); + m_errors++; + } + } +} + +void P2_Config::parse_xml_element_proxy(void *xml_ptr) +{ + xmlNodePtr ptr = (xmlNodePtr) xml_ptr; + + for (ptr = ptr->children; ptr; ptr = ptr->next) + { + if (ptr->type != XML_ELEMENT_NODE) + continue; + if (!strcmp((const char *) ptr->name, "target")) + { + P2_ConfigTarget *t = new P2_ConfigTarget(); + + struct _xmlAttr *attr; + for (attr = ptr->properties; attr; attr = attr->next) + if (!strcmp((const char *) attr->name, "name") + || !strcmp((const char *) attr->name, "host")) + { + parse_xml_text(attr, t->m_virt_address); + } + else if (!strcmp((const char *) attr->name, "database")) + { + parse_xml_text(attr, t->m_virt_database); + } + else if (!strcmp((const char *) attr->name, "default")) + { + parse_xml_text(attr, t->m_default); + } + else if (!strcmp((const char *) attr->name, "type")) + { + parse_xml_text(attr, t->m_type); + } + else + { + yaz_log(YLOG_WARN, "Unknown attribute '%s' for " + "element proxy", + (const char *) attr->name); + m_errors++; + } + parse_xml_element_target(ptr, t); + m_target_list.push_back(t); + } + else if (!strcmp((const char *) ptr->name, "max-clients")) + { + string v; + if (parse_xml_text(ptr, v)) + m_max_clients = atoi(v.c_str()); + } + else if (!strcmp((const char *) ptr->name, "module")) + { + P2_ConfigModule *t = new P2_ConfigModule(); + + string v; + if (parse_xml_text(ptr, v)) + { + t->m_fname = v; + m_modules.push_back(t); + } + } + else + { + yaz_log(YLOG_WARN, "Unknown element '%s' inside proxy", ptr->name); + m_errors++; + } + } +} + +void P2_Config::print() +{ + cout << "max_clients=" << m_max_clients << endl; + list::const_iterator it; + + for (it = m_target_list.begin(); it != m_target_list.end(); it++) + { + cout << "type=" << (*it)->m_type << " "; + cout << "v-address=" << (*it)->m_virt_address << " "; + cout << "v-db=" << (*it)->m_virt_database << " "; + cout << "t-address=" << (*it)->m_target_address << " "; + cout << "t-db=" << (*it)->m_target_database << " "; + cout << "default=" << (*it)->m_default << endl; + } +} + +bool P2_Config::read_xml_config(const char *fname) +{ + xmlDocPtr ndoc = xmlParseFile(fname); + + if (!ndoc) + { + yaz_log(YLOG_WARN, "Config file %s not found or parse error", fname); + return false; + } + int noSubstitutions = xmlXIncludeProcess(ndoc); + if (noSubstitutions == -1) + yaz_log(YLOG_WARN, "XInclude processing failed on config %s", fname); + + xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc); + if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE || + strcmp((const char *) proxyPtr->name, "proxy")) + { + yaz_log(YLOG_WARN, "No proxy element in %s", fname); + xmlFreeDoc(ndoc); + return false; + } + m_rep->m_proxyPtr = proxyPtr; + + // OK: release previous and make it the current one. + if (m_rep->m_docPtr) + xmlFreeDoc(m_rep->m_docPtr); + m_rep->m_docPtr = ndoc; + + m_errors = 0; + parse_xml_element_proxy(proxyPtr); + if (m_errors && !m_debug_mode) + return false; + return true; +} + +P2_Config::~P2_Config() +{ + delete m_rep; +} + +P2_ConfigTarget::P2_ConfigTarget() +{ + m_default = false; +} + +P2_ConfigTarget *P2_Config::find_target(string db) +{ + list::const_iterator it; + for (it = m_target_list.begin(); it != m_target_list.end(); it++) + { + if ((*it)->m_virt_database == db) + return (*it); + } + return 0; +} + + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_config.h b/src/p2_config.h new file mode 100644 index 0000000..f4976e6 --- /dev/null +++ b/src/p2_config.h @@ -0,0 +1,90 @@ +/* $Id: p2_config.h,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef P2_CONFIG_INCLUDED +#define P2_CONFIG_INCLUDED + +#include +#include + +class P2_ConfigTarget { + public: + P2_ConfigTarget(); + std::string m_virt_address; + std::string m_virt_database; + std::string m_target_address; + std::string m_target_database; + std::string m_type; + bool m_default; +}; + +class P2_ConfigModule { + public: + std::string m_fname; +}; + +class P2_Config { + class Rep; + public: + P2_Config::P2_Config(); + P2_Config::~P2_Config(); + bool P2_Config::parse_options(int argc, char **argv); + P2_ConfigTarget *find_target(std::string db); + void print(); + private: + bool read_xml_config(const char *fname); + void parse_xml_element_proxy(void *xml_ptr); + void parse_xml_element_target(void *xml_ptr, + P2_ConfigTarget *t); + bool parse_xml_text(void *xml_ptr, std::string &val); + bool parse_xml_text(void *xml_ptr, bool &val); + public: + std::string m_apdu_log; + std::string m_default_target; + std::string m_listen_address; + std::string m_log_file; + std::string m_optimize_flags; + std::string m_pid_fname; + std::string m_uid; + std::string m_xml_fname; + + int m_max_clients; + int m_client_idletime; + int m_debug_mode; + int m_no_limit_files; + int m_no_threads; + int m_target_idletime; + + std::list m_target_list; + std::list m_modules; + private: + Rep *m_rep; + int m_errors; +}; + +#endif +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_frontend.cpp b/src/p2_frontend.cpp new file mode 100644 index 0000000..274b3d5 --- /dev/null +++ b/src/p2_frontend.cpp @@ -0,0 +1,95 @@ +/* $Id: p2_frontend.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include +#include "p2_frontend.h" + +using namespace yazpp_1; +using namespace std; + +P2_Frontend::P2_Frontend(IPDU_Observable *the_PDU_Observable, + Msg_Thread *my_thread, P2_Server *server) + : Z_Assoc(the_PDU_Observable) +{ + m_my_thread = my_thread; + m_server = server; + m_no_requests = 0; + m_delete_flag = 0; + yaz_log(YLOG_LOG, "Construct P2_Frontend=%p", this); +} + + +IPDU_Observer *P2_Frontend::sessionNotify(IPDU_Observable + *the_PDU_Observable, int fd) +{ + return 0; +} + +P2_Frontend::~P2_Frontend() +{ + yaz_log(YLOG_LOG, "Destroy P2_Frontend=%p", this); + + list::iterator it; + + for (it = m_resultSets.begin(); it != m_resultSets.end(); it++) + { + delete *it; + *it = 0; + } +} + +void P2_Frontend::recv_GDU(Z_GDU *z_pdu, int len) +{ + GDU *gdu = new GDU(z_pdu); + + P2_Msg *m = new P2_Msg(gdu, this, m_server); + m_no_requests++; + m_my_thread->put(m); +} + +void P2_Frontend::failNotify() +{ + m_delete_flag = 1; + if (m_no_requests == 0) + delete this; + +} + +void P2_Frontend::timeoutNotify() +{ + m_delete_flag = 1; + if (m_no_requests == 0) + delete this; +} + +void P2_Frontend::connectNotify() +{ + +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_frontend.h b/src/p2_frontend.h new file mode 100644 index 0000000..fe403e6 --- /dev/null +++ b/src/p2_frontend.h @@ -0,0 +1,163 @@ +/* $Id: p2_frontend.h,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef P2_FRONTEND_H +#define P2_FRONTEND_H + +#include +#include +#include + +#include "msg-thread.h" +#include +#include +#include +#include + +class P2_Frontend; +class P2_Server; +class P2_Config; +class P2_ConfigTarget; +class P2_ModuleFactory; + +class IP2_BackendSet; + +class P2_BackendResultSet { + public: + P2_BackendResultSet(); + ~P2_BackendResultSet(); + yazpp_1::Yaz_Z_Query m_query; + std::list m_db_list; + int m_hit_count; + IP2_BackendSet *m_int; + // record cache here +}; + +class IP2_Backend; + +class P2_Backend { + public: + P2_Backend(P2_ConfigTarget *cfg, IP2_Backend *backend_interface); + ~P2_Backend(); + public: + std::listm_resultSets; + P2_ConfigTarget *m_configTarget; + bool m_busy; + IP2_Backend *m_int; +}; + +class P2_Server : public yazpp_1::Z_Assoc { +public: + ~P2_Server(); + P2_Server(yazpp_1::IPDU_Observable *the_PDU_Observable, + Msg_Thread *m_my_thread, + P2_Config *config, + P2_ModuleFactory *modules); + P2_Config *lockConfig(); + void unlockConfig(); + std::listm_backend_list; + P2_ModuleFactory *m_modules; +private: + yazpp_1::IPDU_Observer* sessionNotify( + yazpp_1::IPDU_Observable *the_PDU_Observable, + int fd); + void recv_GDU(Z_GDU *apdu, int len); + + void failNotify(); + void timeoutNotify(); + void connectNotify(); +private: + P2_Config *m_config; + Msg_Thread *m_my_thread; + pthread_mutex_t m_mutex_config; +}; + +class P2_FrontResultSet { +public: + P2_FrontResultSet(const char *id); + ~P2_FrontResultSet(); + void setQuery(Z_Query *z_query); + void setDatabases(char **db, int num); + std::string m_resultSetId; + std::vector m_db_list; + yazpp_1::Yaz_Z_Query m_query; +}; + +class P2_Msg : public IMsg_Thread { +public: + int m_close_flag; + yazpp_1::GDU *m_gdu; + yazpp_1::GDU *m_output; + P2_Frontend *m_front; + P2_Server *m_server; + IMsg_Thread *handle(); + void result(); + P2_Msg(yazpp_1::GDU *gdu, P2_Frontend *front, P2_Server *server); + virtual ~P2_Msg(); + private: + + Z_APDU *frontend_search_resultset(Z_APDU *z_gdu, ODR odr, + P2_FrontResultSet **rset); + Z_APDU *frontend_present_resultset(Z_APDU *z_gdu, ODR odr, + P2_FrontResultSet **rset); + Z_APDU *frontend_search_apdu(Z_APDU *z_gdu, ODR odr); + Z_APDU *frontend_present_apdu(Z_APDU *z_gdu, ODR odr); + P2_Backend *select_backend(std::string db, + yazpp_1::Yaz_Z_Query *query, + P2_BackendResultSet **bset); + P2_Backend *create_backend(std::string db); +}; + +class P2_Frontend : public yazpp_1::Z_Assoc { + public: + ~P2_Frontend(); + P2_Frontend(yazpp_1::IPDU_Observable *the_PDU_Observable, + Msg_Thread *m_my_thread, P2_Server *server); + IPDU_Observer* sessionNotify(yazpp_1::IPDU_Observable *the_PDU_Observable, + int fd); + + void recv_GDU(Z_GDU *apdu, int len); + + void failNotify(); + void timeoutNotify(); + void connectNotify(); + + int m_no_requests; + int m_delete_flag; + std::list m_resultSets; + + private: + yazpp_1::GDUQueue m_in_queue; + Msg_Thread *m_my_thread; + P2_Server *m_server; + private: + bool P2_Frontend::search(Z_GDU *z_gdu); + bool P2_Frontend::handle_init(Z_GDU *z_gdu); +}; + +#endif +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_modules.cpp b/src/p2_modules.cpp new file mode 100644 index 0000000..6f1778b --- /dev/null +++ b/src/p2_modules.cpp @@ -0,0 +1,77 @@ + +#include + +#include "p2_modules.h" + +class P2_ModuleDLEntry { +public: + void *m_dl_handle; + P2_ModuleEntry *m_entry; + P2_ModuleDLEntry(); + ~P2_ModuleDLEntry(); +}; + +P2_ModuleDLEntry::P2_ModuleDLEntry() +{ + m_dl_handle = 0; + m_entry = 0; +} + +P2_ModuleDLEntry::~P2_ModuleDLEntry() +{ + if (m_dl_handle) + dlclose(m_dl_handle); +} + +P2_ModuleFactory::P2_ModuleFactory() +{ +} + +P2_ModuleFactory::~P2_ModuleFactory() +{ +} + +bool P2_ModuleFactory::add(P2_ModuleEntry *entry) +{ + P2_ModuleDLEntry *m = new P2_ModuleDLEntry(); + m->m_entry = entry; + m_modules.push_back(m); + return true; +} + +bool P2_ModuleFactory::add(const char *fname) +{ + void *dl_handle = dlopen(fname, RTLD_NOW|RTLD_GLOBAL); + if (!dl_handle) + return false; + + P2_ModuleEntry *entry = + reinterpret_cast + (dlsym(dl_handle, "p2_module_entry")); + if (!entry) + { + dlclose(dl_handle); + return false; + } + P2_ModuleDLEntry *m = new P2_ModuleDLEntry(); + m->m_dl_handle = dl_handle; + m->m_entry = entry; + m_modules.push_back(m); + return true; +} + +void *P2_ModuleFactory::get_interface(const char *name, int version) +{ + std::list::const_iterator it; + for (it = m_modules.begin(); it != m_modules.end(); it++) + { + P2_ModuleDLEntry *ent = *it; + if (!strcmp(ent->m_entry->name, name) && + ent->m_entry->version == version) + { + return ent->m_entry->interface_ptr; + } + } + return 0; +} + diff --git a/src/p2_modules.h b/src/p2_modules.h new file mode 100644 index 0000000..c3f0e1b --- /dev/null +++ b/src/p2_modules.h @@ -0,0 +1,21 @@ + +#ifndef P2_MODULES_H +#define P2_MODULES_H + +#include "p2_backend.h" + +#include + +class P2_ModuleDLEntry ; +class P2_ModuleFactory { + public: + P2_ModuleFactory(); + ~P2_ModuleFactory(); + bool add(const char *fname); + bool add(P2_ModuleEntry *entry); + void *get_interface(const char *name, int version); + private: + std::list m_modules; +}; + +#endif diff --git a/src/p2_msg.cpp b/src/p2_msg.cpp new file mode 100644 index 0000000..e113a21 --- /dev/null +++ b/src/p2_msg.cpp @@ -0,0 +1,387 @@ +/* $Id: p2_msg.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include +#include "p2_backend.h" +#include "p2_frontend.h" +#include "p2_config.h" +#include "p2_modules.h" + +using namespace yazpp_1; +using namespace std; + +IP2_BackendSet::~IP2_BackendSet() +{ +} + +IP2_Backend::~IP2_Backend() +{ + +} + +P2_Backend::P2_Backend(P2_ConfigTarget *cfg, IP2_Backend *backend_int) +{ + m_configTarget = new P2_ConfigTarget; + *m_configTarget = *cfg; + m_busy = false; + m_int = backend_int; +} + +P2_Backend::~P2_Backend() +{ + delete m_configTarget; +} + +P2_BackendResultSet::P2_BackendResultSet() +{ + m_int = 0; +} + +P2_BackendResultSet::~P2_BackendResultSet() +{ + delete m_int; +} + +P2_Backend *P2_Msg::select_backend(string db, + Yaz_Z_Query *query, + P2_BackendResultSet **bset) +{ + P2_Config *cfg = m_server->lockConfig(); + + // see if some target has done this query before + + *bset = 0; + P2_Backend *backend = 0; + + list::const_iterator it; + for (it = m_server->m_backend_list.begin(); + it != m_server->m_backend_list.end(); it++) + { + if ((*it)->m_busy) + continue; + + if (db != (*it)->m_configTarget->m_virt_database) + continue; + backend = *it; + + if (query) + { + list::const_iterator is; + for (is = (*it)->m_resultSets.begin(); + is != (*it)->m_resultSets.end(); is++) + { + if (query->match(&(*is)->m_query)) + { + *bset = *is; + break; + } + } + } + if (bset) + break; + } + if (!backend) + { + P2_ConfigTarget *target_cfg = cfg->find_target(db); + + if (!target_cfg) + { + yaz_log(YLOG_WARN, "No backend for database %s", + db.c_str()); + } + else + { + P2_ModuleInterface0 *int0 = + reinterpret_cast + (m_server->m_modules->get_interface(target_cfg->m_type.c_str(), + 0)); + IP2_Backend *bint = 0; + + if (int0) + bint = int0->create(target_cfg->m_target_address.c_str()); + + if (bint) + backend = new P2_Backend(target_cfg, bint); + + if (backend) + m_server->m_backend_list.push_back(backend); + } + } + if (backend) + backend->m_busy = true; + m_server->unlockConfig(); + return backend; +} + +void P2_FrontResultSet::setQuery(Z_Query *z_query) +{ + m_query.set_Z_Query(z_query); +} + +void P2_FrontResultSet::setDatabases(char **db, int num) +{ + m_db_list.clear(); + + int i; + for (i = 0; iu.searchRequest; + list::iterator it; + P2_FrontResultSet *s = 0; + + string id = req->resultSetName; + for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++) + { + if ((*it)->m_resultSetId == id) + { + s = *it; + break; + } + } + if (s) + { + // result set already exists + *rset = s; + if (req->replaceIndicator && *req->replaceIndicator) + { // replace indicator true + s->setQuery(req->query); + s->setDatabases(req->databaseNames, req->num_databaseNames); + return 0; + } + Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse); + Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records)); + apdu->u.searchResponse->records = rec; + rec->which = Z_Records_NSD; + rec->u.nonSurrogateDiagnostic = + zget_DefaultDiagFormat( + odr, YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF, + req->resultSetName); + + return apdu; + } + // does not exist + s = new P2_FrontResultSet(req->resultSetName); + s->setQuery(req->query); + s->setDatabases(req->databaseNames, req->num_databaseNames); + m_front->m_resultSets.push_back(s); + *rset = s; + return 0; +} + +Z_APDU *P2_Msg::frontend_search_apdu(Z_APDU *request_apdu, ODR odr) +{ + P2_FrontResultSet *rset; + Z_APDU *response_apdu = frontend_search_resultset(request_apdu, odr, + &rset); + if (response_apdu) + return response_apdu; + + // no immediate error (yet) + size_t i; + for (i = 0; im_db_list.size(); i++) + { + string db = rset->m_db_list[i]; + P2_BackendResultSet *bset; + P2_Backend *b = select_backend(db, &rset->m_query, &bset); + if (!b) + { + Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse); + Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records)); + apdu->u.searchResponse->records = rec; + rec->which = Z_Records_NSD; + rec->u.nonSurrogateDiagnostic = + zget_DefaultDiagFormat( + odr, YAZ_BIB1_DATABASE_UNAVAILABLE, db.c_str()); + return apdu; + } + if (!bset) + { // new set + bset = new P2_BackendResultSet(); + + bset->m_query.set_Z_Query(request_apdu->u.searchRequest->query); + bset->m_db_list.push_back(db); + + b->m_int->search(&bset->m_query, &bset->m_int, &bset->m_hit_count); + b->m_resultSets.push_back(bset); + } + else + { + bset->m_int->get(1, 1); + } + response_apdu = zget_APDU(odr, Z_APDU_searchResponse); + *response_apdu->u.searchResponse->resultCount = bset->m_hit_count; + b->m_busy = false; + } + if (!response_apdu) + { + Z_APDU *apdu = zget_APDU(odr, Z_APDU_searchResponse); + Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records)); + apdu->u.searchResponse->records = rec; + rec->which = Z_Records_NSD; + rec->u.nonSurrogateDiagnostic = + zget_DefaultDiagFormat(odr, YAZ_BIB1_UNSUPP_SEARCH, 0); + return apdu; + } + return response_apdu; +} + +Z_APDU *P2_Msg::frontend_present_resultset(Z_APDU *z_gdu, ODR odr, + P2_FrontResultSet **rset) +{ + Z_PresentRequest *req = z_gdu->u.presentRequest; + list::iterator it; + P2_FrontResultSet *s = 0; + + string id = req->resultSetId; + for (it = m_front->m_resultSets.begin(); it != m_front->m_resultSets.end(); it++) + { + if ((*it)->m_resultSetId == id) + { + s = *it; + break; + } + } + *rset = s; + if (s) + return 0; // fine result set exists + + Z_APDU *apdu = zget_APDU(odr, Z_APDU_presentResponse); + + Z_Records *rec = (Z_Records *) odr_malloc(odr, sizeof(Z_Records)); + apdu->u.presentResponse->records = rec; + rec->which = Z_Records_NSD; + rec->u.nonSurrogateDiagnostic = + zget_DefaultDiagFormat( + odr, + YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST, + req->resultSetId); + return apdu; +} + +Z_APDU *P2_Msg::frontend_present_apdu(Z_APDU *request_apdu, ODR odr) +{ + P2_FrontResultSet *rset; + Z_APDU *response_apdu = frontend_present_resultset(request_apdu, odr, + &rset); + if (response_apdu) + return response_apdu; + return zget_APDU(odr, Z_APDU_presentResponse); +} + +IMsg_Thread *P2_Msg::handle() +{ + ODR odr = odr_createmem(ODR_ENCODE); + yaz_log(YLOG_LOG, "P2_Msg:handle begin"); + Z_GDU *request_gdu = m_gdu->get(); + + if (request_gdu->which == Z_GDU_Z3950) + { + Z_APDU *request_apdu = request_gdu->u.z3950; + Z_APDU *response_apdu = 0; + switch(request_apdu->which) + { + case Z_APDU_initRequest: + response_apdu = zget_APDU(odr, Z_APDU_initResponse); + ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_triggerResourceCtrl); + ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_search); + ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_present); + ODR_MASK_SET(response_apdu->u.initResponse->options, Z_Options_namedResultSets); + break; + case Z_APDU_searchRequest: + response_apdu = frontend_search_apdu(request_apdu, odr); + break; + case Z_APDU_presentRequest: + response_apdu = frontend_present_apdu(request_apdu, odr); + break; + case Z_APDU_triggerResourceControlRequest: + break; + default: + response_apdu = zget_APDU(odr, Z_APDU_close); + m_close_flag = 1; + break; + } + if (response_apdu) + m_output = new GDU(response_apdu); + } + yaz_log(YLOG_LOG, "P2_Msg:handle end"); + odr_destroy(odr); + return this; +} + +void P2_Msg::result() +{ + m_front->m_no_requests--; + if (!m_front->m_delete_flag) + { + if (m_output) + { + int len; + m_front->send_GDU(m_output->get(), &len); + } + if (m_close_flag) + { + m_front->close(); + m_front->m_delete_flag = 1; + } + } + if (m_front->m_delete_flag && m_front->m_no_requests == 0) + delete m_front; + delete this; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_xmlerror.cpp b/src/p2_xmlerror.cpp new file mode 100644 index 0000000..d2bcaac --- /dev/null +++ b/src/p2_xmlerror.cpp @@ -0,0 +1,70 @@ +/* $Id: p2_xmlerror.cpp,v 1.1 2005-10-05 12:07:15 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include +#include + +#include "p2_xmlerror.h" + +#if HAVE_XSLT +#include +#include +#endif + +#if HAVE_XSLT +static void p2_xml_error_handler(void *ctx, const char *fmt, ...) +{ + char buf[1024]; + size_t sz; + + va_list ap; + va_start(ap, fmt); + +#ifdef WIN32 + vsprintf(buf, fmt, ap); +#else + vsnprintf(buf, sizeof(buf), fmt, ap); +#endif + sz = strlen(buf); + if (sz > 0 && buf[sz-1] == '\n') + buf[sz-1] = '\0'; + + yaz_log(YLOG_WARN, "%s: %s", (char*) ctx, buf); + + va_end (ap); +} +#endif + +void p2_xmlerror_setup() +{ +#if HAVE_XSLT + xmlSetGenericErrorFunc((void *) "XML", p2_xml_error_handler); + xsltSetGenericErrorFunc((void *) "XSLT", p2_xml_error_handler); +#endif +} +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/p2_xmlerror.h b/src/p2_xmlerror.h new file mode 100644 index 0000000..df6a346 --- /dev/null +++ b/src/p2_xmlerror.h @@ -0,0 +1,35 @@ +/* $Id: p2_xmlerror.h,v 1.1 2005-10-05 12:07:15 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef P2_XMLERROR_H +#define P2_XMLERROR_H + +void p2_xmlerror_setup(); + +#endif + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/t-server.cpp b/src/t-server.cpp index a264ddf..b7133a5 100644 --- a/src/t-server.cpp +++ b/src/t-server.cpp @@ -1,8 +1,8 @@ /* - * Copyright (c) 1998-2005, Index Data. + * Copyright (c) 2005, Index Data. * See the file LICENSE for details. * - * $Id: t-server.cpp,v 1.5 2005-09-26 09:24:14 adam Exp $ + * $Id: t-server.cpp,v 1.6 2005-10-05 12:07:15 adam Exp $ */ #include