Initial checkin of proxy 2 code
[yazproxy-moved-to-github.git] / src / p2_config.cpp
1 /* $Id: p2_config.cpp,v 1.1 2005-10-05 12:07:14 adam Exp $
2    Copyright (c) 1998-2005, Index Data.
3
4 This file is part of the yaz-proxy.
5
6 YAZ proxy is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with YAZ proxy; see the file LICENSE.  If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <yaz/log.h>
25 #include <yaz/options.h>
26 #include <yaz/diagbib1.h>
27 #include "p2_config.h"
28
29 #if HAVE_XSLT
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #include <libxml/xinclude.h>
33 #include <libxslt/xsltutils.h>
34 #include <libxslt/transform.h>
35 #endif
36
37 #include <iostream>
38
39 using namespace std;
40
41 class P2_Config::Rep {
42     
43 public:
44     Rep();
45     ~Rep();
46 public:
47 #if HAVE_XSLT
48     xmlDocPtr m_docPtr;
49     xmlNodePtr m_proxyPtr;
50 #endif
51 };
52
53 P2_Config::Rep::Rep()
54 {
55 #if HAVE_XSLT
56     m_docPtr = 0;
57     m_proxyPtr = 0;
58 #endif
59 }
60
61 P2_Config::Rep::~Rep()
62 {
63 #if HAVE_XSLT
64     if (m_docPtr)
65         xmlFreeDoc(m_docPtr);
66 #endif
67 }
68     
69 P2_Config::P2_Config()
70 {
71     m_max_clients = 500;
72     m_client_idletime = 600;
73     m_debug_mode = 0;
74     m_no_limit_files = 0;
75     m_no_threads = 20;
76     m_target_idletime = 600;
77
78     m_rep = new Rep();
79 }
80
81 bool P2_Config::parse_options(int argc, char **argv)
82 {
83     char *arg;
84     int ret;
85     bool show_config = false;
86     while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:n:h:XS",
87                           argv, argc, &arg)) != -2)
88     {
89         switch (ret)
90         {
91         case 0:
92             if (m_listen_address.length())
93             {
94                 yaz_log(YLOG_FATAL, "Multiple listener address given");
95                 return false;
96             }
97             m_listen_address = arg;
98             break;
99         case 'a':
100             m_apdu_log = arg;
101             break;
102         case 'c':
103             if (m_xml_fname.length())
104             {
105                 yaz_log(YLOG_FATAL, "Multiple -c options given");
106                 return false;
107             }
108             if (!read_xml_config(arg))
109             {
110                 return false;
111             }
112             m_xml_fname = arg;
113             break;
114         case 'i':
115             m_client_idletime = atoi(arg);
116             break;
117         case 'l':
118             m_log_file = arg;
119             break;
120         case 'm':
121             m_max_clients = atoi(arg);
122             break;
123         case 'n':
124             m_no_limit_files = atoi(arg);
125             break;
126         case 'h':
127             m_no_threads = atoi(arg);
128             break;
129         case 'o':
130             m_optimize_flags = arg;
131             break;
132         case 'p':
133             if (m_pid_fname.length())
134             {
135                 yaz_log(YLOG_LOG, "Multiple -p options given");
136                 return false;
137             }
138             m_pid_fname = arg;
139             break;
140         case 't':
141             if (m_default_target.length())
142             {
143                 yaz_log(YLOG_LOG, "Multiple -t options given");
144                 return false;
145             }
146             m_default_target = arg;
147             break;
148         case 'T':
149             m_target_idletime = atoi(arg);
150             break;
151         case 'u':
152             if (m_uid.length())
153             {
154                 yaz_log(YLOG_FATAL, "-u specified more than once");
155                 return false;
156             }
157             m_uid = arg;
158             break;
159         case 'v':
160             yaz_log_init_level(yaz_log_mask_str(arg));
161             break;
162         case 'X':
163             m_debug_mode = 1;
164             break;
165         case 'S':
166             show_config = true;
167             break;
168         default:
169             yaz_log(YLOG_FATAL, "Bad option %s", arg);
170             return false;
171         }
172     } 
173     if (m_log_file.length())
174         yaz_log_init_file(m_log_file.c_str());
175     if (show_config)
176         print();
177     return true;
178 }
179
180 bool P2_Config::parse_xml_text(void *xml_ptr, bool &val)
181 {
182     string v;
183     if (!parse_xml_text(xml_ptr, v))
184         return false;
185     if (v.length() == 1 && v[0] == '1')
186         val = true;
187     else
188         val = false;
189     return true;
190 }
191
192 bool P2_Config::parse_xml_text(void *xml_ptr, string &val)
193 {
194     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
195     bool found = false;
196     string v;
197     for(ptr = ptr->children; ptr; ptr = ptr->next)
198         if (ptr->type == XML_TEXT_NODE)
199         {
200             xmlChar *t = ptr->content;
201             if (t)
202             {
203                 v += (const char *) t;
204                 found = true;
205             }
206         }
207     if (found)
208         val = v;
209     return found;
210 }
211
212 void P2_Config::parse_xml_element_target(void *xml_ptr,
213                                          P2_ConfigTarget *t)
214 {
215     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
216
217     for (ptr = ptr->children; ptr; ptr = ptr->next)
218     {
219         if (ptr->type != XML_ELEMENT_NODE)
220             continue;
221         if (!strcmp((const char *) ptr->name, "url"))
222         {
223             parse_xml_text(ptr, t->m_target_address);
224         }
225         else if (!strcmp((const char *) ptr->name, "database"))
226         {
227             parse_xml_text(ptr, t->m_target_database);
228         }
229         else
230         {
231             yaz_log(YLOG_WARN, "Unknown element '%s' inside target",
232                     (const char *) ptr->name);
233             m_errors++;
234         }
235     }
236 }
237
238 void P2_Config::parse_xml_element_proxy(void *xml_ptr)
239 {
240     xmlNodePtr ptr = (xmlNodePtr) xml_ptr;
241
242     for (ptr = ptr->children; ptr; ptr = ptr->next)
243     {
244         if (ptr->type != XML_ELEMENT_NODE)
245             continue;
246         if (!strcmp((const char *) ptr->name, "target"))
247         {
248             P2_ConfigTarget *t = new P2_ConfigTarget();
249
250             struct _xmlAttr *attr;
251             for (attr = ptr->properties; attr; attr = attr->next)
252                 if (!strcmp((const char *) attr->name, "name")
253                     || !strcmp((const char *) attr->name, "host"))
254                 {
255                     parse_xml_text(attr, t->m_virt_address);
256                 }
257                 else if (!strcmp((const char *) attr->name, "database"))
258                 {
259                     parse_xml_text(attr, t->m_virt_database);
260                 }
261                 else if (!strcmp((const char *) attr->name, "default"))
262                 {
263                     parse_xml_text(attr, t->m_default);
264                 }
265                 else if (!strcmp((const char *) attr->name, "type"))
266                 {
267                     parse_xml_text(attr, t->m_type);
268                 }
269                 else
270                 {
271                     yaz_log(YLOG_WARN, "Unknown attribute '%s' for "
272                             "element proxy",
273                             (const char *) attr->name);
274                     m_errors++;
275                 }
276             parse_xml_element_target(ptr, t);
277             m_target_list.push_back(t);
278         }
279         else if (!strcmp((const char *) ptr->name, "max-clients"))
280         {
281             string v;
282             if (parse_xml_text(ptr, v))
283                 m_max_clients = atoi(v.c_str());
284         }
285         else if (!strcmp((const char *) ptr->name, "module"))
286         {
287             P2_ConfigModule *t = new P2_ConfigModule();
288
289             string v;
290             if (parse_xml_text(ptr, v))
291             {
292                 t->m_fname = v;
293                 m_modules.push_back(t);
294             }
295         }
296         else
297         {
298             yaz_log(YLOG_WARN, "Unknown element '%s' inside proxy", ptr->name);
299             m_errors++;
300         }
301     }
302 }
303
304 void P2_Config::print()
305 {
306     cout << "max_clients=" << m_max_clients << endl;
307     list<P2_ConfigTarget *>::const_iterator it;
308     
309     for (it = m_target_list.begin(); it != m_target_list.end(); it++)
310     {
311         cout << "type=" << (*it)->m_type << " ";
312         cout << "v-address=" << (*it)->m_virt_address << " ";
313         cout << "v-db=" << (*it)->m_virt_database << " ";
314         cout << "t-address=" << (*it)->m_target_address << " ";
315         cout << "t-db=" << (*it)->m_target_database << " ";
316         cout << "default=" << (*it)->m_default << endl;
317     }
318 }
319
320 bool P2_Config::read_xml_config(const char *fname)
321 {
322     xmlDocPtr ndoc = xmlParseFile(fname);
323
324     if (!ndoc)
325     {
326         yaz_log(YLOG_WARN, "Config file %s not found or parse error", fname);
327         return false;
328     }
329     int noSubstitutions = xmlXIncludeProcess(ndoc);
330     if (noSubstitutions == -1)
331         yaz_log(YLOG_WARN, "XInclude processing failed on config %s", fname);
332
333     xmlNodePtr proxyPtr = xmlDocGetRootElement(ndoc);
334     if (!proxyPtr || proxyPtr->type != XML_ELEMENT_NODE ||
335         strcmp((const char *) proxyPtr->name, "proxy"))
336     {
337         yaz_log(YLOG_WARN, "No proxy element in %s", fname);
338         xmlFreeDoc(ndoc);
339         return false;
340     }
341     m_rep->m_proxyPtr = proxyPtr;
342     
343     // OK: release previous and make it the current one.
344     if (m_rep->m_docPtr)
345         xmlFreeDoc(m_rep->m_docPtr);
346     m_rep->m_docPtr = ndoc;
347
348     m_errors = 0;
349     parse_xml_element_proxy(proxyPtr);
350     if (m_errors && !m_debug_mode)
351         return false;
352     return true;
353 }
354
355 P2_Config::~P2_Config()
356 {
357     delete m_rep;
358 }
359
360 P2_ConfigTarget::P2_ConfigTarget()
361 {
362     m_default = false;
363 }
364
365 P2_ConfigTarget *P2_Config::find_target(string db)
366 {
367     list<P2_ConfigTarget *>::const_iterator it;
368     for (it = m_target_list.begin(); it != m_target_list.end(); it++)
369     {
370         if ((*it)->m_virt_database == db)
371             return (*it);
372     }
373     return 0;
374 }
375
376
377 /*
378  * Local variables:
379  * c-basic-offset: 4
380  * indent-tabs-mode: nil
381  * End:
382  * vim: shiftwidth=4 tabstop=8 expandtab
383  */