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