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