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