Log XSLT errors to log
[yazpp-moved-to-github.git] / src / yaz-proxy-main.cpp
1 /*
2  * Copyright (c) 1998-2004, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-proxy-main.cpp,v 1.35 2004-03-17 10:49:58 adam Exp $
6  */
7
8 #include <signal.h>
9 #include <unistd.h>
10 #include <pwd.h>
11 #include <sys/types.h>
12 #include <stdarg.h>
13
14 #if HAVE_GETRLIMIT
15 #include <sys/time.h>
16 #include <sys/resource.h>
17 #endif
18
19 #include <yaz/log.h>
20 #include <yaz/options.h>
21
22 #include <yaz++/socket-manager.h>
23 #include <yaz++/pdu-assoc.h>
24 #include <yaz++/proxy.h>
25
26 void usage(char *prog)
27 {
28     fprintf (stderr, "%s: [-c config] [-l log] [-a log] [-v level] [-t target] "
29              "[-u uid] [-p pidfile] @:port\n", prog);
30     exit (1);
31 }
32
33 static char *pid_fname = 0;
34 static char *uid = 0;
35 static char *log_file = 0;
36 static int debug = 0;
37 static int no_limit_files = 0;
38
39 int args(Yaz_Proxy *proxy, int argc, char **argv)
40 {
41     char *addr = 0;
42     char *arg;
43     char *prog = argv[0];
44     int ret;
45
46     while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:U:n:X",
47                           argv, argc, &arg)) != -2)
48     {
49         int err;
50         switch (ret)
51         {
52         case 0:
53             if (addr)
54             {
55                 usage(prog);
56                 return 1;
57             }
58             addr = arg;
59             break;
60         case 'c':
61             err = proxy->set_config(arg);
62             if (err == -2)
63             {
64                 fprintf(stderr, "Config file support not enabled (proxy not compiled with libxml2 support)\n");
65                 exit(1);
66             }
67             else if (err == -1)
68             {
69                 fprintf(stderr, "Bad or missing file %s\n", arg);
70                 exit(1);
71             }
72             break;
73         case 'a':
74             proxy->set_APDU_log(arg);
75             break;
76         case 't':
77             proxy->set_default_target(arg);
78             break;
79         case 'U':
80             proxy->set_proxy_authentication(arg);
81             break;
82         case 'o':
83             proxy->option("optimize", arg);
84             break;
85         case 'v':
86             yaz_log_init_level (yaz_log_mask_str(arg));
87             break;
88         case 'l':
89             yaz_log_init_file (arg);
90             log_file = xstrdup(arg);
91             break;
92         case 'm':
93             proxy->set_max_clients(atoi(arg));
94             break;
95         case 'i':
96             proxy->set_client_idletime(atoi(arg));
97             break;
98         case 'T':
99             proxy->set_target_idletime(atoi(arg));
100             break;
101         case 'n':
102             no_limit_files = atoi(arg);
103             break;
104         case 'X':
105             debug = 1;
106             break;
107         case 'p':
108             if (!pid_fname)
109                 pid_fname = xstrdup(arg);
110             break;
111         case 'u':
112             if (!uid)
113                 uid = xstrdup(arg);
114             break;
115         default:
116             usage(prog);
117             return 1;
118         }
119     }
120     if (addr)
121     {
122         if (proxy->server(addr))
123         {
124             yaz_log(LOG_FATAL|LOG_ERRNO, "listen %s", addr);
125             exit(1);
126         }
127     }
128     else
129     {
130         usage(prog);
131         return 1;
132     }
133     return 0;
134 }
135
136 static Yaz_Proxy *static_yaz_proxy = 0;
137 static void sighup_handler(int num)
138 {
139     signal(SIGHUP, sighup_handler);
140     if (static_yaz_proxy)
141         static_yaz_proxy->reconfig();
142 }
143
144 #if HAVE_XSLT
145 static void proxy_xml_error_handler(void *ctx, const char *fmt, ...)
146 {
147     char buf[1024];
148
149     va_list ap;
150     va_start(ap, fmt);
151
152     vsnprintf(buf, sizeof(buf), fmt, ap);
153
154     yaz_log(LOG_WARN, "%s: %s", (char*) ctx, buf);
155
156     va_end (ap);
157 }
158 #endif
159
160 static void child_run(Yaz_SocketManager *m, int run)
161 {
162     signal(SIGHUP, sighup_handler);
163
164 #if HAVE_XSLT
165     xmlSetGenericErrorFunc((void *) "XML", proxy_xml_error_handler);
166     xsltSetGenericErrorFunc((void *) "XSLT", proxy_xml_error_handler);
167 #endif
168     yaz_log(LOG_LOG, "0 proxy run=%d pid=%ld", run, (long) getpid());
169
170     if (no_limit_files)
171     {
172 #if HAVE_SETRLIMIT
173         struct rlimit limit_data;
174         limit_data.rlim_cur = no_limit_files;
175         limit_data.rlim_max = no_limit_files;
176         
177         yaz_log(LOG_LOG, "0 setrlimit NOFILE cur=%d max=%d",
178                 limit_data.rlim_cur, limit_data.rlim_max);
179         if (setrlimit(RLIMIT_NOFILE, &limit_data))
180             yaz_log(LOG_ERRNO|LOG_WARN, "setrlimit");
181 #else
182         yaz_log(LOG_WARN, "setrlimit unavablable. Option -n ignored");
183 #endif
184     }
185     if (pid_fname)
186     {
187         FILE *f = fopen(pid_fname, "w");
188         if (!f)
189         {
190             yaz_log(LOG_ERRNO|LOG_FATAL, "Couldn't create %s", pid_fname);
191             exit(0);
192         }
193         fprintf(f, "%ld", (long) getpid());
194         fclose(f);
195         xfree(pid_fname);
196     }
197     if (uid)
198     {
199         struct passwd *pw;
200
201         if (!(pw = getpwnam(uid)))
202         {
203             yaz_log(LOG_FATAL, "%s: Unknown user", uid);
204             exit(3);
205         }
206         if (log_file)
207         {
208             chown(log_file, pw->pw_uid,  pw->pw_gid);
209             xfree(log_file);
210         }
211         if (setuid(pw->pw_uid) < 0)
212         {
213             yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
214             exit(4);
215         }
216         xfree(uid);
217     }
218 #if HAVE_GETRLIMIT
219     struct rlimit limit_data;
220     getrlimit(RLIMIT_NOFILE, &limit_data);
221     yaz_log(LOG_LOG, "0 getrlimit NOFILE cur=%d max=%d",
222             limit_data.rlim_cur, limit_data.rlim_max);
223 #endif
224     
225     while (m->processEvent() > 0)
226         ;
227
228     exit (0);
229 }
230
231 int main(int argc, char **argv)
232 {
233 #if HAVE_XSLT
234     xmlInitMemory();
235     
236     LIBXML_TEST_VERSION
237 #endif
238     int cont = 1;
239     int run = 1;
240     Yaz_SocketManager mySocketManager;
241     Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
242
243     static_yaz_proxy = &proxy;
244
245     args(&proxy, argc, argv);
246
247     if (debug)
248     {
249         child_run(&mySocketManager, run);
250         exit(0);
251     }
252     while (cont)
253     {
254         pid_t p = fork();
255         if (p == (pid_t) -1)
256         {
257             yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
258             exit(1);
259         }
260         else if (p == 0)
261         {
262             child_run(&mySocketManager, run);
263         }
264         pid_t p1;
265         int status;
266         p1 = wait(&status);
267
268         yaz_log_reopen();
269
270         if (p1 != p)
271         {
272             yaz_log(LOG_FATAL, "p1=%d != p=%d", p1, p);
273             exit(1);
274         }
275         if (WIFSIGNALED(status))
276         {
277             switch(WTERMSIG(status)) {
278             case SIGILL:
279                 yaz_log(LOG_WARN, "Received SIGILL from child %ld", (long) p);
280                 cont = 1;
281                 break;
282             case SIGABRT:
283                 yaz_log(LOG_WARN, "Received SIGABRT from child %ld", (long) p);
284                 cont = 1;
285                 break ;
286             case SIGSEGV:
287                 yaz_log(LOG_WARN, "Received SIGSEGV from child %ld", (long) p);
288                 cont = 1;
289                 break;
290             case SIGBUS:        
291                 yaz_log(LOG_WARN, "Received SIGBUS from child %ld", (long) p);
292                 cont = 1;
293                 break;
294             case SIGTERM:
295                 yaz_log(LOG_LOG, "Received SIGTERM from child %ld",
296                         (long) p);
297                 cont = 0;
298                 break;
299             default:
300                 yaz_log(LOG_WARN, "Received SIG %d from child %ld",
301                         WTERMSIG(status), (long) p);
302                 cont = 0;
303             }
304         }
305         else if (status == 0)
306             cont = 0;
307         else
308         {
309             yaz_log(LOG_LOG, "Exit %d from child %ld", status, (long) p);
310             cont = 1;
311         }
312         if (cont)
313             sleep(1 + run/5);
314         run++;
315     }
316     exit (0);
317     return 0;
318 }