Initial checkin of proxy 2 code
[yazproxy-moved-to-github.git] / src / p2_config.cpp
diff --git a/src/p2_config.cpp b/src/p2_config.cpp
new file mode 100644 (file)
index 0000000..de50049
--- /dev/null
@@ -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 <stdlib.h>
+#include <string.h>
+#include <yaz/log.h>
+#include <yaz/options.h>
+#include <yaz/diagbib1.h>
+#include "p2_config.h"
+
+#if HAVE_XSLT
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xinclude.h>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+#endif
+
+#include <iostream>
+
+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<P2_ConfigTarget *>::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<P2_ConfigTarget *>::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
+ */