Simplify use of iconv for MARC records
[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.34 2004-02-16 10:47:37 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", 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(0, proxy_xml_error_handler);
166 #endif
167     yaz_log(LOG_LOG, "0 proxy run=%d pid=%ld", run, (long) getpid());
168
169     if (no_limit_files)
170     {
171 #if HAVE_SETRLIMIT
172         struct rlimit limit_data;
173         limit_data.rlim_cur = no_limit_files;
174         limit_data.rlim_max = no_limit_files;
175         
176         yaz_log(LOG_LOG, "0 setrlimit NOFILE cur=%d max=%d",
177                 limit_data.rlim_cur, limit_data.rlim_max);
178         if (setrlimit(RLIMIT_NOFILE, &limit_data))
179             yaz_log(LOG_ERRNO|LOG_WARN, "setrlimit");
180 #else
181         yaz_log(LOG_WARN, "setrlimit unavablable. Option -n ignored");
182 #endif
183     }
184     if (pid_fname)
185     {
186         FILE *f = fopen(pid_fname, "w");
187         if (!f)
188         {
189             yaz_log(LOG_ERRNO|LOG_FATAL, "Couldn't create %s", pid_fname);
190             exit(0);
191         }
192         fprintf(f, "%ld", (long) getpid());
193         fclose(f);
194         xfree(pid_fname);
195     }
196     if (uid)
197     {
198         struct passwd *pw;
199
200         if (!(pw = getpwnam(uid)))
201         {
202             yaz_log(LOG_FATAL, "%s: Unknown user", uid);
203             exit(3);
204         }
205         if (log_file)
206         {
207             chown(log_file, pw->pw_uid,  pw->pw_gid);
208             xfree(log_file);
209         }
210         if (setuid(pw->pw_uid) < 0)
211         {
212             yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
213             exit(4);
214         }
215         xfree(uid);
216     }
217 #if HAVE_GETRLIMIT
218     struct rlimit limit_data;
219     getrlimit(RLIMIT_NOFILE, &limit_data);
220     yaz_log(LOG_LOG, "0 getrlimit NOFILE cur=%d max=%d",
221             limit_data.rlim_cur, limit_data.rlim_max);
222 #endif
223     
224     while (m->processEvent() > 0)
225         ;
226
227     exit (0);
228 }
229
230 int main(int argc, char **argv)
231 {
232 #if HAVE_XSLT
233     xmlInitMemory();
234     
235     LIBXML_TEST_VERSION
236 #endif
237     int cont = 1;
238     int run = 1;
239     Yaz_SocketManager mySocketManager;
240     Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
241
242     static_yaz_proxy = &proxy;
243
244     args(&proxy, argc, argv);
245
246     if (debug)
247     {
248         child_run(&mySocketManager, run);
249         exit(0);
250     }
251     while (cont)
252     {
253         pid_t p = fork();
254         if (p == (pid_t) -1)
255         {
256             yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
257             exit(1);
258         }
259         else if (p == 0)
260         {
261             child_run(&mySocketManager, run);
262         }
263         pid_t p1;
264         int status;
265         p1 = wait(&status);
266
267         yaz_log_reopen();
268
269         if (p1 != p)
270         {
271             yaz_log(LOG_FATAL, "p1=%d != p=%d", p1, p);
272             exit(1);
273         }
274         if (WIFSIGNALED(status))
275         {
276             switch(WTERMSIG(status)) {
277             case SIGILL:
278                 yaz_log(LOG_WARN, "Received SIGILL from child %ld", (long) p);
279                 cont = 1;
280                 break;
281             case SIGABRT:
282                 yaz_log(LOG_WARN, "Received SIGABRT from child %ld", (long) p);
283                 cont = 1;
284                 break ;
285             case SIGSEGV:
286                 yaz_log(LOG_WARN, "Received SIGSEGV from child %ld", (long) p);
287                 cont = 1;
288                 break;
289             case SIGBUS:        
290                 yaz_log(LOG_WARN, "Received SIGBUS from child %ld", (long) p);
291                 cont = 1;
292                 break;
293             case SIGTERM:
294                 yaz_log(LOG_LOG, "Received SIGTERM from child %ld",
295                         (long) p);
296                 cont = 0;
297                 break;
298             default:
299                 yaz_log(LOG_WARN, "Received SIG %d from child %ld",
300                         WTERMSIG(status), (long) p);
301                 cont = 0;
302             }
303         }
304         else if (status == 0)
305             cont = 0;
306         else
307         {
308             yaz_log(LOG_LOG, "Exit %d from child %ld", status, (long) p);
309             cont = 1;
310         }
311         if (cont)
312             sleep(1 + run/5);
313         run++;
314     }
315     exit (0);
316     return 0;
317 }