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