llow EXSLT to be used if it's available.
[yazproxy-moved-to-github.git] / src / yaz-proxy-main.cpp
1 /* $Id: yaz-proxy-main.cpp,v 1.21 2007-10-08 11:47:21 adam Exp $
2    Copyright (c) 1998-2006, Index Data.
3
4 This file is part of the yazproxy.
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 <signal.h>
23 #if HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #if HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29 #if HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32 #if HAVE_SYS_WAIT_H
33 #include <sys/wait.h>
34 #endif
35 #if HAVE_SYS_RESOURCE_H
36 #include <sys/resource.h>
37 #endif
38 #if HAVE_PWD_H
39 #include <pwd.h>
40 #endif
41
42 #include <stdarg.h>
43 #include <stdlib.h>
44
45 #include <yaz/log.h>
46 #include <yaz/options.h>
47
48 #include <yazpp/socket-manager.h>
49 #include <yazpp/pdu-assoc.h>
50 #include <yazproxy/proxy.h>
51
52 #if YAZ_HAVE_XSLT
53 #include <libxml/parser.h>
54 #include <libxml/tree.h>
55 #include <libxslt/xsltutils.h>
56 #include <libxslt/transform.h>
57 #endif
58
59 #if YAZ_HAVE_EXSLT
60 #include <libexslt/exslt.h>
61 #endif
62
63 using namespace yazpp_1;
64
65 void usage(char *prog)
66 {
67     fprintf (stderr, "%s: [-a log] [-c config]\n"
68              " [-i sec] [-l log] [-m num] [-n num] [-p pidfile]"
69              " [-t target] [-T sec] [-u uid]\n"
70              " [-v level] [-X] @:port\n", prog);
71     exit (1);
72 }
73
74 static char *pid_fname = 0;
75 static char *uid = 0;
76 static char *log_file = 0;
77 static int debug = 0;
78 static int no_limit_files = 0;
79
80 int args(Yaz_Proxy *proxy, int argc, char **argv)
81 {
82     char *addr = 0;
83     char *arg;
84     char *prog = argv[0];
85     int ret;
86
87     while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:n:X",
88                           argv, argc, &arg)) != -2)
89     {
90         int err;
91         switch (ret)
92         {
93         case 0:
94             if (addr)
95             {
96                 usage(prog);
97                 return 1;
98             }
99             addr = arg;
100             break;
101         case 'a':
102             proxy->set_APDU_log(arg);
103             break;
104         case 'c':
105             err = proxy->set_config(arg);
106             if (err == -2)
107             {
108                 fprintf(stderr, "Config file support not enabled (not using libxslt & libxml2)\n");
109                 exit(1);
110             }
111             else if (err == -1)
112             {
113                 fprintf(stderr, "Bad or missing file %s\n", arg);
114                 exit(1);
115             }
116             break;
117         case 'i':
118             proxy->set_client_idletime(atoi(arg));
119             break;
120         case 'l':
121             yaz_log_init_file (arg);
122             log_file = xstrdup(arg);
123             break;
124         case 'm':
125             proxy->set_max_clients(atoi(arg));
126             break;
127         case 'n':
128             no_limit_files = atoi(arg);
129             break;
130         case 'o':
131             proxy->option("optimize", arg);
132             break;
133         case 'p':
134             if (!pid_fname)
135                 pid_fname = xstrdup(arg);
136             break;
137         case 't':
138             proxy->set_default_target(arg);
139             break;
140         case 'T':
141             proxy->set_target_idletime(atoi(arg));
142             break;
143         case 'u':
144             if (!uid)
145                 uid = xstrdup(arg);
146             break;
147         case 'v':
148             yaz_log_init_level (yaz_log_mask_str(arg));
149             break;
150         case 'X':
151             proxy->set_debug_mode(1);
152             debug = 1;
153             break;
154         default:
155             usage(prog);
156             return 1;
157         }
158     }
159     if (addr)
160     {
161         if (proxy->server(addr))
162         {
163             yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen %s", addr);
164             exit(1);
165         }
166     }
167     else
168     {
169         usage(prog);
170         return 1;
171     }
172     return 0;
173 }
174
175 static Yaz_Proxy *static_yaz_proxy = 0;
176 static void sighup_handler(int num)
177 {
178 #if WIN32
179 #else
180     signal(SIGHUP, sighup_handler);
181 #endif
182     if (static_yaz_proxy)
183         static_yaz_proxy->reconfig();
184 }
185
186 #if YAZ_HAVE_XSLT
187 static void proxy_xml_error_handler(void *ctx, const char *fmt, ...)
188 {
189     char buf[1024];
190
191     va_list ap;
192     va_start(ap, fmt);
193
194 #ifdef WIN32
195     vsprintf(buf, fmt, ap);
196 #else
197     vsnprintf(buf, sizeof(buf), fmt, ap);
198 #endif
199     yaz_log(YLOG_WARN, "%s: %s", (char*) ctx, buf);
200
201     va_end (ap);
202 }
203 #endif
204
205 static void child_run(SocketManager *m, int run)
206 {
207 #ifdef WIN32
208 #else
209     signal(SIGHUP, sighup_handler);
210 #endif
211
212 #if YAZ_HAVE_XSLT
213     xmlSetGenericErrorFunc((void *) "XML", proxy_xml_error_handler);
214     xsltSetGenericErrorFunc((void *) "XSLT", proxy_xml_error_handler);
215 #endif
216
217 #if YAZ_HAVE_EXSLT
218     exsltRegisterAll();
219 #endif
220 #ifdef WIN32
221 #else
222     yaz_log(YLOG_LOG, "0 proxy run=%d pid=%ld", run, (long) getpid());
223 #endif
224     if (no_limit_files)
225     {
226 #if HAVE_SETRLIMIT
227         struct rlimit limit_data;
228         limit_data.rlim_cur = no_limit_files;
229         limit_data.rlim_max = no_limit_files;
230         
231         yaz_log(YLOG_LOG, "0 setrlimit NOFILE cur=%ld max=%ld",
232                 (long) limit_data.rlim_cur, (long) limit_data.rlim_max);
233         if (setrlimit(RLIMIT_NOFILE, &limit_data))
234             yaz_log(YLOG_ERRNO|YLOG_WARN, "setrlimit");
235 #else
236         yaz_log(YLOG_WARN, "setrlimit unavablable. Option -n ignored");
237 #endif
238     }
239 #ifdef WIN32
240 #else
241     if (pid_fname)
242     {
243         FILE *f = fopen(pid_fname, "w");
244         if (!f)
245         {
246             yaz_log(YLOG_ERRNO|YLOG_FATAL, "Couldn't create %s", pid_fname);
247             exit(0);
248         }
249         fprintf(f, "%ld", (long) getpid());
250         fclose(f);
251         xfree(pid_fname);
252     }
253     if (uid)
254     {
255         struct passwd *pw;
256
257         if (!(pw = getpwnam(uid)))
258         {
259             yaz_log(YLOG_FATAL, "%s: Unknown user", uid);
260             exit(3);
261         }
262         if (log_file)
263         {
264             chown(log_file, pw->pw_uid,  pw->pw_gid);
265             xfree(log_file);
266         }
267         if (setuid(pw->pw_uid) < 0)
268         {
269             yaz_log(YLOG_FATAL|YLOG_ERRNO, "setuid");
270             exit(4);
271         }
272         xfree(uid);
273     }
274 #endif
275 #if HAVE_GETRLIMIT
276     struct rlimit limit_data;
277     getrlimit(RLIMIT_NOFILE, &limit_data);
278     yaz_log(YLOG_LOG, "0 getrlimit NOFILE cur=%ld max=%ld",
279             (long) limit_data.rlim_cur, (long) limit_data.rlim_max);
280 #endif
281     
282     while (m->processEvent() > 0)
283         ;
284
285     exit (0);
286 }
287
288 int main(int argc, char **argv)
289 {
290 #if YAZ_HAVE_XSLT
291     xmlInitMemory();
292     
293     LIBXML_TEST_VERSION
294 #endif
295     int cont = 1;
296     int run = 1;
297     SocketManager mySocketManager;
298     Yaz_Proxy proxy(new PDU_Assoc(&mySocketManager), &mySocketManager);
299
300     static_yaz_proxy = &proxy;
301
302     args(&proxy, argc, argv);
303
304 #ifdef WIN32
305     child_run(&mySocketManager, run);
306 #else
307     if (debug)
308     {
309         child_run(&mySocketManager, run);
310         exit(0);
311     }
312     while (cont)
313     {
314         pid_t p = fork();
315         if (p == (pid_t) -1)
316         {
317             yaz_log(YLOG_FATAL|YLOG_ERRNO, "fork");
318             exit(1);
319         }
320         else if (p == 0)
321         {
322             child_run(&mySocketManager, run);
323         }
324         pid_t p1;
325         int status;
326         p1 = wait(&status);
327
328         yaz_log_reopen();
329
330         if (p1 != p)
331         {
332             yaz_log(YLOG_FATAL, "p1=%d != p=%d", p1, p);
333             exit(1);
334         }
335         if (WIFSIGNALED(status))
336         {
337             switch(WTERMSIG(status)) {
338             case SIGILL:
339                 yaz_log(YLOG_WARN, "Received SIGILL from child %ld", (long) p);
340                 cont = 1;
341                 break;
342             case SIGABRT:
343                 yaz_log(YLOG_WARN, "Received SIGABRT from child %ld", (long) p);
344                 cont = 1;
345                 break ;
346             case SIGSEGV:
347                 yaz_log(YLOG_WARN, "Received SIGSEGV from child %ld", (long) p);
348                 cont = 1;
349                 break;
350             case SIGBUS:        
351                 yaz_log(YLOG_WARN, "Received SIGBUS from child %ld", (long) p);
352                 cont = 1;
353                 break;
354             case SIGTERM:
355                 yaz_log(YLOG_LOG, "Received SIGTERM from child %ld",
356                         (long) p);
357                 cont = 0;
358                 break;
359             default:
360                 yaz_log(YLOG_WARN, "Received SIG %d from child %ld",
361                         WTERMSIG(status), (long) p);
362                 cont = 0;
363             }
364         }
365         else if (status == 0)
366             cont = 0;
367         else
368         {
369             yaz_log(YLOG_LOG, "Exit %d from child %ld", status, (long) p);
370             cont = 1;
371         }
372         if (cont)
373             sleep(1 + run/5);
374         run++;
375     }
376 #endif
377     exit (0);
378     return 0;
379 }
380 /*
381  * Local variables:
382  * c-basic-offset: 4
383  * indent-tabs-mode: nil
384  * End:
385  * vim: shiftwidth=4 tabstop=8 expandtab
386  */
387